diff --git a/examples/mobile-viewer/viewer.mjs b/examples/mobile-viewer/viewer.mjs index 32915ebe9cb82..fedd5d8e23ead 100644 --- a/examples/mobile-viewer/viewer.mjs +++ b/examples/mobile-viewer/viewer.mjs @@ -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({ diff --git a/gulpfile.mjs b/gulpfile.mjs index 697a81a461582..8112e8b155bcb 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -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 diff --git a/test/unit/pdf_viewer.component_spec.js b/test/unit/pdf_viewer.component_spec.js index cace29e03b5e8..1785a4959c256 100644 --- a/test/unit/pdf_viewer.component_spec.js +++ b/test/unit/pdf_viewer.component_spec.js @@ -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); - }); }); diff --git a/test/unit/unit_test.html b/test/unit/unit_test.html index add51eb7c1676..d88bd5bfc8f94 100644 --- a/test/unit/unit_test.html +++ b/test/unit/unit_test.html @@ -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", diff --git a/tsconfig.json b/tsconfig.json index 402f13d23c042..4a48983e68e4d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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"] diff --git a/web/annotation_editor_layer_builder.js b/web/annotation_editor_layer_builder.js index d4a2aa9fd6fe6..c841de6ac0f98 100644 --- a/web/annotation_editor_layer_builder.js +++ b/web/annotation_editor_layer_builder.js @@ -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; diff --git a/web/genericl10n.js b/web/genericl10n.js index 7a350b50fec8f..431b1043fca5f 100644 --- a/web/genericl10n.js +++ b/web/genericl10n.js @@ -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, - "en-us", 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 }; + } 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 { baseURL: href.replace(/[^/]*$/, "") || "./", paths }; + return createBundle(lang, text); } } diff --git a/web/l10n.js b/web/l10n.js index 14c09c389d496..7909e43ca31c3 100644 --- a/web/l10n.js +++ b/web/l10n.js @@ -117,4 +117,6 @@ class L10n { } } -export { L10n }; +const GenericL10n = null; + +export { GenericL10n, L10n }; diff --git a/web/l10n_utils.js b/web/l10n_utils.js deleted file mode 100644 index 2e493651eb106..0000000000000 --- a/web/l10n_utils.js +++ /dev/null @@ -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 }; diff --git a/web/pdf_page_view.js b/web/pdf_page_view.js index 1df2f360e2a16..4e97897b5ca2e 100644 --- a/web/pdf_page_view.js +++ b/web/pdf_page_view.js @@ -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); } } diff --git a/web/pdf_viewer.component.js b/web/pdf_viewer.component.js index c10d4aeb6ecee..e3f9e8db8d24b 100644 --- a/web/pdf_viewer.component.js +++ b/web/pdf_viewer.component.js @@ -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, diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 54cf661407fbf..b1943dd9ca15f 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -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); diff --git a/web/stubs.js b/web/stubs.js deleted file mode 100644 index 333ab1a5ece1d..0000000000000 --- a/web/stubs.js +++ /dev/null @@ -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 }; diff --git a/web/viewer-geckoview.html b/web/viewer-geckoview.html index 7076a436bf187..57e28e172d819 100644 --- a/web/viewer-geckoview.html +++ b/web/viewer-geckoview.html @@ -63,7 +63,7 @@ "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", diff --git a/web/viewer.html b/web/viewer.html index ffe19ed97a3e7..d65e56e63711c 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -72,7 +72,7 @@ "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",