Collect all l10n fallback strings, used in the viewer, in one helper function (PR 12981 follow-up)

Rather than having to spell out the English fallback strings at *every* single `IL10n.get` call-site throughout the viewer, we can simplify things by collecting them in *one* central spot.
This provides a much better overview of the fallback l10n strings used, which makes future changes easier and ensures that fallback strings occuring in multiple places cannot accidentally get out of sync.
Furthermore, by making the `fallback` parameter of the `IL10n.get` method *optional*[1] many of the call-sites (and their surrounding code) become a lot less verbose.

---
[1] It's obviously still possible to pass in a fallback string, it's just not required.
This commit is contained in:
Jonas Jenwald 2021-02-22 12:43:16 +01:00
parent 8d203b3039
commit 038668bf8c
17 changed files with 238 additions and 272 deletions

View File

@ -14,7 +14,7 @@
*/
import { AnnotationLayer } from "pdfjs-lib";
import { NullL10n } from "./ui_utils.js";
import { NullL10n } from "./l10n_utils.js";
import { SimpleLinkService } from "./pdf_link_service.js";
/**

View File

@ -260,28 +260,6 @@ const PDFViewerApplication = {
_scriptingInstance: null,
_mouseState: Object.create(null),
_localizeMessage(key, args = null) {
const DEFAULT_L10N_STRINGS = {
error_file: "File: {{file}}",
error_line: "Line: {{line}}",
error_message: "Message: {{message}}",
error_stack: "Stack: {{stack}}",
error_version_info: "PDF.js v{{version}} (build: {{build}})",
invalid_file_error: "Invalid or corrupted PDF file.",
loading_error: "An error occurred while loading the PDF.",
missing_file_error: "Missing PDF file.",
printing_not_ready: "Warning: The PDF is not fully loaded for printing.",
printing_not_supported:
"Warning: Printing is not fully supported by this browser.",
rendering_error: "An error occurred while rendering the page.",
unexpected_response_error: "Unexpected server response.",
web_fonts_disabled:
"Web fonts are disabled: unable to use embedded PDF fonts.",
};
return this.l10n.get(key || "", args, DEFAULT_L10N_STRINGS[key]);
},
// Called once when the document is loaded.
async initialize(appConfig) {
this.preferences = this.externalServices.createPreferences();
@ -741,7 +719,7 @@ const PDFViewerApplication = {
this.open(file, args);
},
onError: err => {
this._localizeMessage("loading_error").then(msg => {
this.l10n.get("loading_error").then(msg => {
this._documentError(msg, err);
});
},
@ -973,7 +951,7 @@ const PDFViewerApplication = {
} else if (exception instanceof UnexpectedResponseException) {
key = "unexpected_response_error";
}
return this._localizeMessage(key).then(msg => {
return this.l10n.get(key).then(msg => {
this._documentError(msg, { message: exception?.message });
throw exception;
});
@ -1128,28 +1106,28 @@ const PDFViewerApplication = {
*/
_otherError(message, moreInfo = null) {
const moreInfoText = [
this._localizeMessage("error_version_info", {
this.l10n.get("error_version_info", {
version: version || "?",
build: build || "?",
}),
];
if (moreInfo) {
moreInfoText.push(
this._localizeMessage("error_message", { message: moreInfo.message })
this.l10n.get("error_message", { message: moreInfo.message })
);
if (moreInfo.stack) {
moreInfoText.push(
this._localizeMessage("error_stack", { stack: moreInfo.stack })
this.l10n.get("error_stack", { stack: moreInfo.stack })
);
} else {
if (moreInfo.filename) {
moreInfoText.push(
this._localizeMessage("error_file", { file: moreInfo.filename })
this.l10n.get("error_file", { file: moreInfo.filename })
);
}
if (moreInfo.lineNumber) {
moreInfoText.push(
this._localizeMessage("error_line", { line: moreInfo.lineNumber })
this.l10n.get("error_line", { line: moreInfo.lineNumber })
);
}
}
@ -2021,7 +1999,7 @@ const PDFViewerApplication = {
}
if (!this.supportsPrinting) {
this._localizeMessage("printing_not_supported").then(msg => {
this.l10n.get("printing_not_supported").then(msg => {
this._otherError(msg);
});
return;
@ -2030,7 +2008,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._localizeMessage("printing_not_ready").then(msg => {
this.l10n.get("printing_not_ready").then(msg => {
// eslint-disable-next-line no-alert
window.alert(msg);
});
@ -2354,7 +2332,7 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
throw new Error("file origin does not match viewer's");
}
} catch (ex) {
PDFViewerApplication._localizeMessage("loading_error").then(msg => {
PDFViewerApplication.l10n.get("loading_error").then(msg => {
PDFViewerApplication._documentError(msg, { message: ex?.message });
});
throw ex;
@ -2465,7 +2443,7 @@ function webViewerInitialized() {
if (!PDFViewerApplication.supportsDocumentFonts) {
AppOptions.set("disableFontFace", true);
PDFViewerApplication._localizeMessage("web_fonts_disabled").then(msg => {
PDFViewerApplication.l10n.get("web_fonts_disabled").then(msg => {
console.warn(msg);
});
}
@ -2497,7 +2475,7 @@ function webViewerInitialized() {
try {
webViewerOpenFileViaURL(file);
} catch (reason) {
PDFViewerApplication._localizeMessage("loading_error").then(msg => {
PDFViewerApplication.l10n.get("loading_error").then(msg => {
PDFViewerApplication._documentError(msg, reason);
});
}
@ -2568,7 +2546,7 @@ function webViewerPageRendered({ pageNumber, timestamp, error }) {
}
if (error) {
PDFViewerApplication._localizeMessage("rendering_error").then(msg => {
PDFViewerApplication.l10n.get("rendering_error").then(msg => {
PDFViewerApplication._otherError(msg, error);
});
}

View File

@ -25,7 +25,6 @@ import {
isValidSpreadMode,
MAX_AUTO_SCALE,
moveToEndOfArray,
NullL10n,
PresentationModeState,
RendererType,
SCROLLBAR_PADDING,
@ -39,6 +38,7 @@ import {
} from "./ui_utils.js";
import { PDFRenderingQueue, RenderingStates } from "./pdf_rendering_queue.js";
import { AnnotationLayerBuilder } from "./annotation_layer_builder.js";
import { NullL10n } from "./l10n_utils.js";
import { PDFPageView } from "./pdf_page_view.js";
import { SimpleLinkService } from "./pdf_link_service.js";
import { TextLayerBuilder } from "./text_layer_builder.js";

View File

@ -18,6 +18,7 @@ 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";
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
throw new Error(
@ -200,8 +201,8 @@ class MozL10n {
return this.mozL10n.getDirection();
}
async get(property, args, fallback) {
return this.mozL10n.get(property, args, fallback);
async get(key, args = null, fallback = getL10nFallback(key, args)) {
return this.mozL10n.get(key, args, fallback);
}
async translate(element) {

View File

@ -14,6 +14,7 @@
*/
import "../external/webL10n/l10n.js";
import { getL10nFallback } from "./l10n_utils.js";
const webL10n = document.webL10n;
@ -37,9 +38,9 @@ class GenericL10n {
return l10n.getDirection();
}
async get(property, args, fallback) {
async get(key, args = null, fallback = getL10nFallback(key, args)) {
const l10n = await this._ready;
return l10n.get(property, args, fallback);
return l10n.get(key, args, fallback);
}
async translate(element) {

127
web/l10n_utils.js Normal file
View File

@ -0,0 +1,127 @@
/* Copyright 2021 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.
*/
/**
* A subset of the l10n strings in the `l10n/en-US/viewer.properties` file.
*/
const DEFAULT_L10N_STRINGS = {
of_pages: "of {{pagesCount}}",
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",
print_progress_percent: "{{progress}}%",
"toggle_sidebar.title": "Toggle Sidebar",
"toggle_sidebar_notification2.title":
"Toggle Sidebar (document contains outline/attachments/layers)",
additional_layers: "Additional Layers",
page_canvas: "Page {{page}}",
thumb_page_title: "Page {{page}}",
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",
error_version_info: "PDF.js v{{version}} (build: {{build}})",
error_message: "Message: {{message}}",
error_stack: "Stack: {{stack}}",
error_file: "File: {{file}}",
error_line: "Line: {{line}}",
rendering_error: "An error occurred while rendering the page.",
page_scale_width: "Page Width",
page_scale_fit: "Page Fit",
page_scale_auto: "Automatic Zoom",
page_scale_actual: "Actual Size",
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.",
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:
"Web fonts are disabled: unable to use embedded PDF fonts.",
};
function getL10nFallback(key, args) {
switch (key) {
case "find_match_count":
key = `find_match_count[${args.total === 1 ? "one" : "other"}]`;
break;
case "find_match_count_limit":
key = `find_match_count_limit[${args.limit === 1 ? "one" : "other"}]`;
break;
}
return DEFAULT_L10N_STRINGS[key] || "";
}
// Replaces {{arguments}} with their values.
function formatL10nValue(text, args) {
if (!args) {
return text;
}
return text.replace(/\{\{\s*(\w+)\s*\}\}/g, (all, name) => {
return name in args ? args[name] : "{{" + name + "}}";
});
}
/**
* No-op implementation of the localization service.
* @implements {IL10n}
*/
const NullL10n = {
async getLanguage() {
return "en-us";
},
async getDirection() {
return "ltr";
},
async get(key, args = null, fallback = getL10nFallback(key, args)) {
return formatL10nValue(fallback, args);
},
async translate(element) {},
};
export { getL10nFallback, NullL10n };

View File

@ -67,34 +67,18 @@ class PasswordPrompt {
);
}
open() {
this.overlayManager.open(this.overlayName).then(() => {
if (
!this._isViewerEmbedded ||
this.reason === PasswordResponses.INCORRECT_PASSWORD
) {
this.input.focus();
}
async open() {
await this.overlayManager.open(this.overlayName);
let promptString;
if (this.reason === PasswordResponses.INCORRECT_PASSWORD) {
promptString = this.l10n.get(
"password_invalid",
null,
"Invalid password. Please try again."
);
} else {
promptString = this.l10n.get(
"password_label",
null,
"Enter the password to open this PDF file."
);
}
const passwordIncorrect =
this.reason === PasswordResponses.INCORRECT_PASSWORD;
promptString.then(msg => {
this.label.textContent = msg;
});
});
if (!this._isViewerEmbedded || passwordIncorrect) {
this.input.focus();
}
this.label.textContent = await this.l10n.get(
`password_${passwordIncorrect ? "invalid" : "label"}`
);
}
close() {

View File

@ -255,27 +255,16 @@ class PDFDocumentProperties {
* @private
*/
async _parseFileSize(fileSize = 0) {
const kb = fileSize / 1024;
const kb = fileSize / 1024,
mb = kb / 1024;
if (!kb) {
return undefined;
} else if (kb < 1024) {
return this.l10n.get(
"document_properties_kb",
{
size_kb: (+kb.toPrecision(3)).toLocaleString(),
size_b: fileSize.toLocaleString(),
},
"{{size_kb}} KB ({{size_b}} bytes)"
);
}
return this.l10n.get(
"document_properties_mb",
{
size_mb: (+(kb / 1024).toPrecision(3)).toLocaleString(),
size_b: fileSize.toLocaleString(),
},
"{{size_mb}} MB ({{size_b}} bytes)"
);
return this.l10n.get(`document_properties_${mb >= 1 ? "mb" : "kb"}`, {
size_mb: mb >= 1 && (+mb.toPrecision(3)).toLocaleString(),
size_kb: (+kb.toPrecision(3)).toLocaleString(),
size_b: fileSize.toLocaleString(),
});
}
/**
@ -304,7 +293,6 @@ class PDFDocumentProperties {
height: Math.round(pageSizeInches.height * 25.4 * 10) / 10,
};
let pageName = null;
let rawName =
getPageName(sizeInches, isPortrait, US_PAGE_NAMES) ||
getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES);
@ -345,46 +333,35 @@ class PDFDocumentProperties {
}
}
}
if (rawName) {
pageName = this.l10n.get(
"document_properties_page_size_name_" + rawName.toLowerCase(),
null,
rawName
);
}
return Promise.all([
const [{ width, height }, unit, name, orientation] = await Promise.all([
this._isNonMetricLocale ? sizeInches : sizeMillimeters,
this.l10n.get(
"document_properties_page_size_unit_" +
(this._isNonMetricLocale ? "inches" : "millimeters"),
null,
this._isNonMetricLocale ? "in" : "mm"
`document_properties_page_size_unit_${
this._isNonMetricLocale ? "inches" : "millimeters"
}`
),
pageName,
rawName &&
this.l10n.get(
`document_properties_page_size_name_${rawName.toLowerCase()}`
),
this.l10n.get(
"document_properties_page_size_orientation_" +
(isPortrait ? "portrait" : "landscape"),
null,
isPortrait ? "portrait" : "landscape"
`document_properties_page_size_orientation_${
isPortrait ? "portrait" : "landscape"
}`
),
]).then(([{ width, height }, unit, name, orientation]) => {
return this.l10n.get(
"document_properties_page_size_dimension_" +
(name ? "name_" : "") +
"string",
{
width: width.toLocaleString(),
height: height.toLocaleString(),
unit,
name,
orientation,
},
"{{width}} × {{height}} {{unit}} (" +
(name ? "{{name}}, " : "") +
"{{orientation}})"
);
});
]);
return this.l10n.get(
`document_properties_page_size_dimension_${name ? "name_" : ""}string`,
{
width: width.toLocaleString(),
height: height.toLocaleString(),
unit,
name,
orientation,
}
);
}
/**
@ -395,14 +372,10 @@ class PDFDocumentProperties {
if (!dateObject) {
return undefined;
}
return this.l10n.get(
"document_properties_date_string",
{
date: dateObject.toLocaleDateString(),
time: dateObject.toLocaleTimeString(),
},
"{{date}}, {{time}}"
);
return this.l10n.get("document_properties_date_string", {
date: dateObject.toLocaleDateString(),
time: dateObject.toLocaleTimeString(),
});
}
/**
@ -410,9 +383,7 @@ class PDFDocumentProperties {
*/
_parseLinearization(isLinearized) {
return this.l10n.get(
"document_properties_linearized_" + (isLinearized ? "yes" : "no"),
null,
isLinearized ? "Yes" : "No"
`document_properties_linearized_${isLinearized ? "yes" : "no"}`
);
}
}

View File

@ -103,41 +103,26 @@ class PDFFindBar {
}
updateUIState(state, previous, matchesCount) {
let findMsg = "";
let findMsg = Promise.resolve("");
let status = "";
switch (state) {
case FindState.FOUND:
break;
case FindState.PENDING:
status = "pending";
break;
case FindState.NOT_FOUND:
findMsg = this.l10n.get("find_not_found", null, "Phrase not found");
findMsg = this.l10n.get("find_not_found");
status = "notFound";
break;
case FindState.WRAPPED:
if (previous) {
findMsg = this.l10n.get(
"find_reached_top",
null,
"Reached top of document, continued from bottom"
);
} else {
findMsg = this.l10n.get(
"find_reached_bottom",
null,
"Reached end of document, continued from top"
);
}
findMsg = this.l10n.get(`find_reached_${previous ? "top" : "bottom"}`);
break;
}
this.findField.setAttribute("data-status", status);
Promise.resolve(findMsg).then(msg => {
findMsg.then(msg => {
this.findMsg.textContent = msg;
this._adjustWidth();
});
@ -147,54 +132,30 @@ class PDFFindBar {
updateResultsCount({ current = 0, total = 0 } = {}) {
const limit = MATCHES_COUNT_LIMIT;
let matchesCountMsg = "";
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.
matchesCountMsg = this.l10n.get(
"find_match_count_limit[other]",
{
limit,
},
"More than {{limit}} matches"
);
} else {
matchesCountMsg = this.l10n.get(
"find_match_count_limit",
{
limit,
},
"More than {{limit}} match" + (limit !== 1 ? "es" : "")
);
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.
matchesCountMsg = this.l10n.get(
"find_match_count[other]",
{
current,
total,
},
"{{current}} of {{total}} matches"
);
} else {
matchesCountMsg = this.l10n.get(
"find_match_count",
{
current,
total,
},
"{{current}} of {{total}} match" + (total !== 1 ? "es" : "")
);
key += "[other]";
}
matchCountMsg = this.l10n.get(key, { current, total });
}
}
Promise.resolve(matchesCountMsg).then(msg => {
matchCountMsg.then(msg => {
this.findResultsCount.textContent = msg;
this.findResultsCount.classList.toggle("hidden", !total);
// Since `updateResultsCount` may be called from `PDFFindController`,

View File

@ -87,11 +87,7 @@ class PDFLayerViewer extends BaseTreeViewer {
element.textContent = this._normalizeTextContent(name);
return;
}
element.textContent = await this.l10n.get(
"additional_layers",
null,
"Additional Layers"
);
element.textContent = await this.l10n.get("additional_layers");
element.style.fontStyle = "italic";
}

View File

@ -18,7 +18,6 @@ import {
CSS_UNITS,
DEFAULT_SCALE,
getOutputScale,
NullL10n,
RendererType,
roundToDivide,
TextLayerMode,
@ -28,6 +27,7 @@ import {
RenderingCancelledException,
SVGGraphics,
} from "pdfjs-lib";
import { NullL10n } from "./l10n_utils.js";
import { RenderingStates } from "./pdf_rendering_queue.js";
import { viewerCompatibilityParams } from "./viewer_compatibility.js";
@ -576,11 +576,9 @@ class PDFPageView {
const viewport = this.viewport;
const canvas = document.createElement("canvas");
this.l10n
.get("page_canvas", { page: this.id }, "Page {{page}}")
.then(msg => {
canvas.setAttribute("aria-label", msg);
});
this.l10n.get("page_canvas", { page: this.id }).then(msg => {
canvas.setAttribute("aria-label", msg);
});
// Keep the canvas hidden until the first draw callback, or until drawing
// is complete when `!this.renderingQueue`, to prevent black flickering.

View File

@ -308,7 +308,7 @@ function renderProgress(index, total, l10n) {
const progressBar = progressContainer.querySelector("progress");
const progressPerc = progressContainer.querySelector(".relative-progress");
progressBar.value = progress;
l10n.get("print_progress_percent", { progress }, progress + "%").then(msg => {
l10n.get("print_progress_percent", { progress }).then(msg => {
progressPerc.textContent = msg;
});
}

View File

@ -339,15 +339,9 @@ class PDFSidebar {
* @private
*/
_showUINotification() {
this.l10n
.get(
"toggle_sidebar_notification2.title",
null,
"Toggle Sidebar (document contains outline/attachments/layers)"
)
.then(msg => {
this.toggleButton.title = msg;
});
this.l10n.get("toggle_sidebar_notification2.title").then(msg => {
this.toggleButton.title = msg;
});
if (!this.isOpen) {
// Only show the notification on the `toggleButton` if the sidebar is
@ -367,11 +361,9 @@ class PDFSidebar {
}
if (reset) {
this.l10n
.get("toggle_sidebar.title", null, "Toggle Sidebar")
.then(msg => {
this.toggleButton.title = msg;
});
this.l10n.get("toggle_sidebar.title").then(msg => {
this.toggleButton.title = msg;
});
}
}

View File

@ -467,19 +467,15 @@ class PDFThumbnailView {
}
get _thumbPageTitle() {
return this.l10n.get(
"thumb_page_title",
{ page: this.pageLabel ?? this.id },
"Page {{page}}"
);
return this.l10n.get("thumb_page_title", {
page: this.pageLabel ?? this.id,
});
}
get _thumbPageCanvas() {
return this.l10n.get(
"thumb_page_canvas",
{ page: this.pageLabel ?? this.id },
"Thumbnail of Page {{page}}"
);
return this.l10n.get("thumb_page_canvas", {
page: this.pageLabel ?? this.id,
});
}
/**

View File

@ -21,10 +21,11 @@ import {
DefaultTextLayerFactory,
TextLayerBuilder,
} from "./text_layer_builder.js";
import { EventBus, NullL10n, ProgressBar } from "./ui_utils.js";
import { EventBus, ProgressBar } from "./ui_utils.js";
import { PDFLinkService, SimpleLinkService } from "./pdf_link_service.js";
import { DownloadManager } from "./download_manager.js";
import { GenericL10n } from "./genericl10n.js";
import { NullL10n } from "./l10n_utils.js";
import { PDFFindController } from "./pdf_find_controller.js";
import { PDFHistory } from "./pdf_history.js";
import { PDFPageView } from "./pdf_page_view.js";

View File

@ -177,26 +177,18 @@ class Toolbar {
items.pageNumber.type = "text";
} else {
items.pageNumber.type = "number";
this.l10n
.get("of_pages", { pagesCount }, "of {{pagesCount}}")
.then(msg => {
items.numPages.textContent = msg;
});
this.l10n.get("of_pages", { pagesCount }).then(msg => {
items.numPages.textContent = msg;
});
}
items.pageNumber.max = pagesCount;
}
if (this.hasPageLabels) {
items.pageNumber.value = this.pageLabel;
this.l10n
.get(
"page_of_pages",
{ pageNumber, pagesCount },
"({{pageNumber}} of {{pagesCount}})"
)
.then(msg => {
items.numPages.textContent = msg;
});
this.l10n.get("page_of_pages", { pageNumber, pagesCount }).then(msg => {
items.numPages.textContent = msg;
});
} else {
items.pageNumber.value = pageNumber;
}
@ -207,9 +199,8 @@ class Toolbar {
items.zoomOut.disabled = pageScale <= MIN_SCALE;
items.zoomIn.disabled = pageScale >= MAX_SCALE;
const customScale = Math.round(pageScale * 10000) / 100;
this.l10n
.get("page_scale_percent", { scale: customScale }, "{{scale}}%")
.get("page_scale_percent", { scale: Math.round(pageScale * 10000) / 100 })
.then(msg => {
let predefinedValueFound = false;
for (const option of items.scaleSelect.options) {
@ -242,10 +233,10 @@ class Toolbar {
const { items, l10n } = this;
const predefinedValuesPromise = Promise.all([
l10n.get("page_scale_auto", null, "Automatic Zoom"),
l10n.get("page_scale_actual", null, "Actual Size"),
l10n.get("page_scale_fit", null, "Page Fit"),
l10n.get("page_scale_width", null, "Page Width"),
l10n.get("page_scale_auto"),
l10n.get("page_scale_actual"),
l10n.get("page_scale_fit"),
l10n.get("page_scale_width"),
]);
// The temporary canvas is used to measure text length in the DOM.

View File

@ -69,36 +69,6 @@ const SpreadMode = {
// Used by `PDFViewerApplication`, and by the API unit-tests.
const AutoPrintRegExp = /\bprint\s*\(/;
// Replaces {{arguments}} with their values.
function formatL10nValue(text, args) {
if (!args) {
return text;
}
return text.replace(/\{\{\s*(\w+)\s*\}\}/g, (all, name) => {
return name in args ? args[name] : "{{" + name + "}}";
});
}
/**
* No-op implementation of the localization service.
* @implements {IL10n}
*/
const NullL10n = {
async getLanguage() {
return "en-us";
},
async getDirection() {
return "ltr";
},
async get(property, args, fallback) {
return formatL10nValue(fallback, args);
},
async translate(element) {},
};
/**
* Returns scale factor for the canvas. It makes sense for the HiDPI displays.
* @returns {Object} The object with horizontal (sx) and vertical (sy)
@ -1057,7 +1027,6 @@ export {
noContextMenuHandler,
normalizeWheelEventDelta,
normalizeWheelEventDirection,
NullL10n,
parseQueryString,
PresentationModeState,
ProgressBar,