fluent-utils.mjs (4197B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { DOMLocalization } from "@fluent/dom"; 6 import { FluentBundle, FluentResource } from "@fluent/bundle"; 7 import { addons } from "@storybook/addons"; 8 import { PSEUDO_STRATEGY_TRANSFORMS } from "./l10n-pseudo.mjs"; 9 import { 10 FLUENT_SET_STRINGS, 11 UPDATE_STRATEGY_EVENT, 12 STRATEGY_DEFAULT, 13 PSEUDO_STRATEGIES, 14 } from "./addon-fluent/constants.mjs"; 15 16 let loadedResources = new Map(); 17 let currentStrategy; 18 let storybookBundle = new FluentBundle("en-US", { 19 transform(str) { 20 if (currentStrategy in PSEUDO_STRATEGY_TRANSFORMS) { 21 return PSEUDO_STRATEGY_TRANSFORMS[currentStrategy](str); 22 } 23 return str; 24 }, 25 }); 26 27 // Listen for update events from addon-fluent. 28 const channel = addons.getChannel(); 29 channel.on(UPDATE_STRATEGY_EVENT, updatePseudoStrategy); 30 channel.on(FLUENT_SET_STRINGS, ftlContents => { 31 let resource = new FluentResource(ftlContents); 32 for (let message of resource.body) { 33 let existingMessage = storybookBundle.getMessage(message.id); 34 existingMessage.value = message.value; 35 existingMessage.attributes = message.attributes; 36 } 37 document.l10n.translateRoots(); 38 }); 39 40 /** 41 * Updates "currentStrategy" when the selected pseudo localization strategy 42 * changes, which in turn changes the transform used by the Fluent bundle. 43 * 44 * @param {string} strategy 45 * Pseudo localization strategy. Can be "default", "accented", or "bidi". 46 */ 47 function updatePseudoStrategy(strategy = STRATEGY_DEFAULT) { 48 if (strategy !== currentStrategy && PSEUDO_STRATEGIES.includes(strategy)) { 49 currentStrategy = strategy; 50 document.l10n.translateRoots(); 51 } 52 } 53 54 export function connectFluent() { 55 document.l10n = new DOMLocalization([], generateBundles); 56 document.l10n.connectRoot(document.documentElement); 57 document.l10n.translateRoots(); 58 } 59 60 function* generateBundles() { 61 yield* [storybookBundle]; 62 } 63 64 export async function insertFTLIfNeeded(fileName) { 65 if (loadedResources.has(fileName)) { 66 return; 67 } 68 69 // This should be browser, locales-preview or toolkit. 70 let [root, ...rest] = fileName.split("/"); 71 let ftlContents; 72 73 // TODO(mstriemer): These seem like they could be combined but I don't want 74 // to fight with webpack anymore. 75 if (root == "toolkit") { 76 // eslint-disable-next-line no-unsanitized/method 77 let imported = await import( 78 /* webpackInclude: /.*[\/\\].*\.ftl$/ */ 79 `toolkit/locales/en-US/${fileName}` 80 ); 81 ftlContents = imported.default; 82 } else if (root == "browser") { 83 // eslint-disable-next-line no-unsanitized/method 84 let imported = await import( 85 /* webpackInclude: /.*[\/\\].*\.ftl$/ */ 86 `browser/locales/en-US/${fileName}` 87 ); 88 ftlContents = imported.default; 89 } else if (root == "locales-preview") { 90 // eslint-disable-next-line no-unsanitized/method 91 let imported = await import( 92 /* webpackInclude: /\.ftl$/ */ 93 `browser/locales-preview/${rest}` 94 ); 95 ftlContents = imported.default; 96 } else if (root == "branding") { 97 // eslint-disable-next-line no-unsanitized/method 98 let imported = await import( 99 /* webpackInclude: /\.ftl$/ */ 100 `browser/branding/nightly/locales/en-US/${rest}` 101 ); 102 ftlContents = imported.default; 103 } else if (root == "preview") { 104 // eslint-disable-next-line no-unsanitized/method 105 let imported = await import( 106 /* webpackInclude: /\.ftl$/ */ 107 `toolkit/components/satchel/megalist/content/${rest}` 108 ); 109 ftlContents = imported.default; 110 } 111 112 if (loadedResources.has(fileName)) { 113 // Seems possible we've attempted to load this twice before the first call 114 // resolves, so once the first load is complete we can abandon the others. 115 return; 116 } 117 118 provideFluent(ftlContents, fileName); 119 } 120 121 export function provideFluent(ftlContents, fileName) { 122 let ftlResource = new FluentResource(ftlContents); 123 storybookBundle.addResource(ftlResource); 124 if (fileName) { 125 loadedResources.set(fileName, ftlResource); 126 } 127 document.l10n.translateRoots(); 128 return ftlResource; 129 }