Merge pull request #17603 from Snuffleupagus/GenericL10n-fallback

Ensure that `GenericL10n` works if the locale files cannot be loaded
This commit is contained in:
Jonas Jenwald 2024-01-31 15:16:48 +01:00 committed by GitHub
commit 9588bceff5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 78 additions and 155 deletions

View File

@ -272,7 +272,7 @@ const PDFViewerApplication = {
});
this.pdfLinkService = linkService;
this.l10n = pdfjsViewer.NullL10n;
this.l10n = new pdfjsViewer.GenericL10n();
const container = document.getElementById("viewerContainer");
const pdfViewer = new pdfjsViewer.PDFViewer({

View File

@ -272,7 +272,7 @@ function createWebpackConfig(
"web-com": "",
"web-download_manager": "",
"web-external_services": "",
"web-l10n_utils": "web/stubs.js",
"web-null_l10n": "",
"web-pdf_attachment_viewer": "web/pdf_attachment_viewer.js",
"web-pdf_cursor_tools": "web/pdf_cursor_tools.js",
"web-pdf_document_properties": "web/pdf_document_properties.js",
@ -294,6 +294,7 @@ function createWebpackConfig(
viewerAlias["web-com"] = "web/chromecom.js";
viewerAlias["web-download_manager"] = "web/download_manager.js";
viewerAlias["web-external_services"] = "web/chromecom.js";
viewerAlias["web-null_l10n"] = "web/l10n.js";
viewerAlias["web-preferences"] = "web/chromecom.js";
viewerAlias["web-print_service"] = "web/pdf_print_service.js";
} else if (bundleDefines.GENERIC) {
@ -308,13 +309,12 @@ function createWebpackConfig(
viewerAlias["web-com"] = "web/genericcom.js";
viewerAlias["web-download_manager"] = "web/download_manager.js";
viewerAlias["web-external_services"] = "web/genericcom.js";
viewerAlias["web-l10n_utils"] = "web/l10n_utils.js";
viewerAlias["web-null_l10n"] = "web/genericl10n.js";
viewerAlias["web-preferences"] = "web/genericcom.js";
viewerAlias["web-print_service"] = "web/pdf_print_service.js";
} else if (bundleDefines.MOZCENTRAL) {
if (bundleDefines.GECKOVIEW) {
const gvAlias = {
"web-l10n_utils": "web/stubs.js",
"web-toolbar": "web/toolbar-geckoview.js",
};
for (const key in viewerAlias) {
@ -324,6 +324,7 @@ function createWebpackConfig(
viewerAlias["web-com"] = "web/firefoxcom.js";
viewerAlias["web-download_manager"] = "web/firefoxcom.js";
viewerAlias["web-external_services"] = "web/firefoxcom.js";
viewerAlias["web-null_l10n"] = "web/l10n.js";
viewerAlias["web-preferences"] = "web/firefoxcom.js";
viewerAlias["web-print_service"] = "web/firefox_print_service.js";
}
@ -1616,7 +1617,7 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
"display-node_utils": "./node_utils.js",
"fluent-bundle": "../../../node_modules/@fluent/bundle/esm/index.js",
"fluent-dom": "../../../node_modules/@fluent/dom/esm/index.js",
"web-l10n_utils": "../web/l10n_utils.js",
"web-null_l10n": "../web/genericl10n.js",
},
};
const licenseHeaderLibre = fs

View File

@ -30,8 +30,6 @@ import { AnnotationLayerBuilder } from "../../web/annotation_layer_builder.js";
import { DownloadManager } from "../../web/download_manager.js";
import { EventBus } from "../../web/event_utils.js";
import { GenericL10n } from "../../web/genericl10n.js";
import { L10n } from "../../web/l10n.js";
import { NullL10n } from "../../web/l10n_utils.js";
import { PDFHistory } from "../../web/pdf_history.js";
import { PDFPageView } from "../../web/pdf_page_view.js";
import { PDFScriptingManager } from "../../web/pdf_scripting_manager.component.js";
@ -54,7 +52,6 @@ describe("pdfviewer_api", function () {
FindState,
GenericL10n,
LinkTarget,
NullL10n,
parseQueryString,
PDFFindController,
PDFHistory,
@ -73,14 +70,4 @@ describe("pdfviewer_api", function () {
XfaLayerBuilder,
});
});
it("checks that `NullL10n` implements all methods", function () {
const methods = Object.getOwnPropertyNames(NullL10n).sort();
const baseMethods = Object.getOwnPropertyNames(L10n.prototype)
.filter(m => m !== "constructor" && !m.startsWith("_"))
.sort();
expect(methods).toEqual(baseMethods);
});
});

View File

@ -30,7 +30,7 @@
"web-com": "../../web/genericcom.js",
"web-download_manager": "../../web/download_manager.js",
"web-external_services": "../../web/genericcom.js",
"web-l10n_utils": "../../web/l10n_utils.js",
"web-null_l10n": "../../web/genericl10n.js",
"web-pdf_attachment_viewer": "../../web/pdf_attachment_viewer.js",
"web-pdf_cursor_tools": "../../web/pdf_cursor_tools.js",
"web-pdf_document_properties": "../../web/pdf_document_properties.js",

View File

@ -16,7 +16,7 @@
"display-node_utils": ["./src/display/node_utils"],
"fluent-bundle": ["./node_modules/@fluent/bundle/esm/index.js"],
"fluent-dom": ["./node_modules/@fluent/dom/esm/index.js"],
"web-l10n_utils": ["./web/l10n_utils"]
"web-null_l10n": ["../web/genericl10n.js"]
}
},
"files": ["src/pdf.js", "web/pdf_viewer.component.js"]

View File

@ -25,7 +25,7 @@
/** @typedef {import("../src/display/annotation_layer.js").AnnotationLayer} AnnotationLayer */
import { AnnotationEditorLayer } from "pdfjs-lib";
import { NullL10n } from "web-l10n_utils";
import { GenericL10n } from "web-null_l10n";
/**
* @typedef {Object} AnnotationEditorLayerBuilderOptions
@ -55,7 +55,10 @@ class AnnotationEditorLayerBuilder {
this.pageDiv = options.pageDiv;
this.pdfPage = options.pdfPage;
this.accessibilityManager = options.accessibilityManager;
this.l10n = options.l10n || NullL10n;
this.l10n = options.l10n;
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
this.l10n ||= new GenericL10n();
}
this.annotationEditorLayer = null;
this.div = null;
this._cancelled = false;

View File

@ -20,22 +20,34 @@ import { DOMLocalization } from "fluent-dom";
import { fetchData } from "pdfjs-lib";
import { L10n } from "./l10n.js";
function createBundle(lang, 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;
}
/**
* @implements {IL10n}
*/
class GenericL10n extends L10n {
constructor(lang) {
super({ lang });
this._setL10n(
new DOMLocalization(
[],
GenericL10n.#generateBundles.bind(
const generateBundles = !lang
? GenericL10n.#generateBundlesFallback.bind(
GenericL10n,
this.getLanguage()
)
: GenericL10n.#generateBundles.bind(
GenericL10n,
"en-us",
this.getLanguage()
)
)
);
);
this._setL10n(new DOMLocalization([], generateBundles));
}
/**
@ -63,6 +75,9 @@ class GenericL10n extends L10n {
if (bundle) {
yield bundle;
}
if (lang === "en-us") {
yield this.#createBundleFallback(lang);
}
}
}
@ -74,20 +89,36 @@ class GenericL10n extends L10n {
const url = new URL(path, baseURL);
const text = await fetchData(url, /* type = */ "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;
return createBundle(lang, text);
}
static async #getPaths() {
const { href } = document.querySelector(`link[type="application/l10n"]`);
const paths = await fetchData(href, /* type = */ "json");
try {
const { href } = document.querySelector(`link[type="application/l10n"]`);
const paths = await fetchData(href, /* type = */ "json");
return { baseURL: href.replace(/[^/]*$/, "") || "./", paths };
return { baseURL: href.replace(/[^/]*$/, "") || "./", paths };
} catch {}
return { baseURL: "./", paths: Object.create(null) };
}
static async *#generateBundlesFallback(lang) {
yield this.#createBundleFallback(lang);
}
static async #createBundleFallback(lang) {
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
throw new Error("Not implemented: #createBundleFallback");
}
const text =
typeof PDFJSDev === "undefined"
? await fetchData(
new URL(`./locale/${lang}/viewer.ftl`, window.location.href),
/* type = */ "text"
)
: PDFJSDev.eval("DEFAULT_FTL");
return createBundle(lang, text);
}
}

View File

@ -117,4 +117,6 @@ class L10n {
}
}
export { L10n };
const GenericL10n = null;
export { GenericL10n, L10n };

View File

@ -1,87 +0,0 @@
/* 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.
*/
/** @typedef {import("./interfaces").IL10n} IL10n */
import { fetchData, shadow } from "pdfjs-lib";
import { FluentBundle, FluentResource } from "fluent-bundle";
import { DOMLocalization } from "fluent-dom";
import { L10n } from "./l10n.js";
/**
* @implements {IL10n}
*/
class ConstL10n extends L10n {
constructor(lang) {
super({ lang });
this._setL10n(
new DOMLocalization([], ConstL10n.#generateBundles.bind(ConstL10n, lang))
);
}
static async *#generateBundles(lang) {
const text =
typeof PDFJSDev === "undefined"
? await fetchData(
new URL(`./locale/${lang}/viewer.ftl`, window.location.href),
/* type = */ "text"
)
: PDFJSDev.eval("DEFAULT_FTL");
const resource = new FluentResource(text);
const bundle = new FluentBundle(lang);
const errors = bundle.addResource(resource);
if (errors.length) {
console.error("L10n errors", errors);
}
yield bundle;
}
static get instance() {
return shadow(this, "instance", new ConstL10n("en-us"));
}
}
/**
* No-op implementation of the localization service.
* @implements {IL10n}
*/
const NullL10n = {
getLanguage() {
return ConstL10n.instance.getLanguage();
},
getDirection() {
return ConstL10n.instance.getDirection();
},
async get(ids, args = null, fallback) {
return ConstL10n.instance.get(ids, args, fallback);
},
async translate(element) {
return ConstL10n.instance.translate(element);
},
pause() {
return ConstL10n.instance.pause();
},
resume() {
return ConstL10n.instance.resume();
},
};
export { NullL10n };

View File

@ -43,7 +43,7 @@ import { AnnotationEditorLayerBuilder } from "./annotation_editor_layer_builder.
import { AnnotationLayerBuilder } from "./annotation_layer_builder.js";
import { compatibilityParams } from "./app_options.js";
import { DrawLayerBuilder } from "./draw_layer_builder.js";
import { NullL10n } from "web-l10n_utils";
import { GenericL10n } from "web-null_l10n";
import { SimpleLinkService } from "./pdf_link_service.js";
import { StructTreeLayerBuilder } from "./struct_tree_layer_builder.js";
import { TextAccessibilityManager } from "./text_accessibility.js";
@ -157,7 +157,10 @@ class PDFPageView {
this.eventBus = options.eventBus;
this.renderingQueue = options.renderingQueue;
this.l10n = options.l10n || NullL10n;
this.l10n = options.l10n;
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
this.l10n ||= new GenericL10n();
}
this.renderTask = null;
this.resume = null;
@ -214,7 +217,7 @@ class PDFPageView {
}
// Ensure that Fluent is connected in e.g. the COMPONENTS build.
if (this.l10n === NullL10n) {
if (!options.l10n) {
this.l10n.translate(this.div);
}
}

View File

@ -30,7 +30,6 @@ import { AnnotationLayerBuilder } from "./annotation_layer_builder.js";
import { DownloadManager } from "./download_manager.js";
import { EventBus } from "./event_utils.js";
import { GenericL10n } from "./genericl10n.js";
import { NullL10n } from "./l10n_utils.js";
import { PDFHistory } from "./pdf_history.js";
import { PDFPageView } from "./pdf_page_view.js";
import { PDFScriptingManager } from "./pdf_scripting_manager.component.js";
@ -54,7 +53,6 @@ export {
FindState,
GenericL10n,
LinkTarget,
NullL10n,
parseQueryString,
PDFFindController,
PDFHistory,

View File

@ -63,7 +63,7 @@ import {
VERTICAL_PADDING,
watchScroll,
} from "./ui_utils.js";
import { NullL10n } from "web-l10n_utils";
import { GenericL10n } from "web-null_l10n";
import { PDFPageView } from "./pdf_page_view.js";
import { PDFRenderingQueue } from "./pdf_rendering_queue.js";
import { SimpleLinkService } from "./pdf_link_service.js";
@ -286,7 +286,10 @@ class PDFViewer {
this.removePageBorders = options.removePageBorders || false;
}
this.maxCanvasPixels = options.maxCanvasPixels;
this.l10n = options.l10n || NullL10n;
this.l10n = options.l10n;
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
this.l10n ||= new GenericL10n();
}
this.#enablePermissions = options.enablePermissions || false;
this.pageColors = options.pageColors || null;
@ -327,7 +330,7 @@ class PDFViewer {
if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) &&
this.l10n === NullL10n
!options.l10n
) {
// Ensure that Fluent is connected in e.g. the COMPONENTS build.
this.l10n.translate(this.container);

View File

@ -1,18 +0,0 @@
/* 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.
*/
const NullL10n = null;
export { NullL10n };

View File

@ -63,7 +63,7 @@ See https://github.com/adobe-type-tools/cmap-resources
"web-com": "./genericcom.js",
"web-download_manager": "./download_manager.js",
"web-external_services": "./genericcom.js",
"web-l10n_utils": "./l10n_utils.js",
"web-null_l10n": "./genericl10n.js",
"web-pdf_attachment_viewer": "./stubs-geckoview.js",
"web-pdf_cursor_tools": "./stubs-geckoview.js",
"web-pdf_document_properties": "./stubs-geckoview.js",

View File

@ -72,7 +72,7 @@ See https://github.com/adobe-type-tools/cmap-resources
"web-com": "./genericcom.js",
"web-download_manager": "./download_manager.js",
"web-external_services": "./genericcom.js",
"web-l10n_utils": "./l10n_utils.js",
"web-null_l10n": "./genericl10n.js",
"web-pdf_attachment_viewer": "./pdf_attachment_viewer.js",
"web-pdf_cursor_tools": "./pdf_cursor_tools.js",
"web-pdf_document_properties": "./pdf_document_properties.js",