• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / blurts-server / #11898

pending completion
#11898

push

circleci

web-flow
Merge pull request #2770 from mozilla/license

Add license headers in source files

282 of 1138 branches covered (24.78%)

Branch coverage included in aggregate %.

959 of 3049 relevant lines covered (31.45%)

2.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/utils/fluent.js
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 { join, resolve } from 'node:path'
6
import { readdirSync } from 'node:fs'
7
import { readFile } from 'node:fs/promises'
8
import { FluentBundle, FluentResource } from '@fluent/bundle'
9
import { negotiateLanguages } from '@fluent/langneg'
10
import AppConstants from '../app-constants.js'
11
import { localStorage } from './local-storage.js'
12

13
const supportedLocales = AppConstants.SUPPORTED_LOCALES?.split(',')
×
14
const fluentBundles = {}
×
15

16
/**
17
* Create Fluent bundles for all supported locales.
18
* Reads .ftl files in parallel for better server start performance.
19
*/
20
async function initFluentBundles () {
21
  const promises = supportedLocales.map(async locale => {
×
22
    const bundle = new FluentBundle(locale, { useIsolating: false })
×
23
    const dirname = resolve('../locales', locale)
×
24

25
    try {
×
26
      const filenames = readdirSync(dirname).filter(item => item.endsWith('.ftl'))
×
27

28
      await Promise.all(filenames.map(async filename => {
×
29
        const str = await readFile(join(dirname, filename), 'utf8')
×
30

31
        bundle.addResource(new FluentResource(str))
×
32
      }))
33
    } catch (e) {
34
      console.error('Could not read Fluent file:', e)
×
35
      throw new Error(e)
×
36
    }
37

38
    fluentBundles[locale] = bundle
×
39
  })
40

41
  await Promise.allSettled(promises)
×
42

43
  console.log('Fluent bundles created:', Object.keys(fluentBundles))
×
44
}
45

46
/**
47
* Set the locale used for translations negotiated between requested and available
48
* @param {Array} requestedLocales - Locales requested by client.
49
*/
50
function updateLocale (requestedLocales) {
51
  return negotiateLanguages(
×
52
    requestedLocales,
53
    supportedLocales,
54
    { strategy: 'lookup', defaultLocale: 'en' }
55
  )
56
}
57

58
/**
59
* Return the locale negotiated between requested and supported locales.
60
* Default 'en' if localStorage hasn't initialized (called without client request)
61
*/
62
function getLocale () {
63
  return localStorage.getStore()?.get('locale') || 'en'
×
64
}
65

66
/**
67
* Translate a message and return the raw string
68
* Defaults to en if message id not found in requested locale
69
* @param {string} id - The Fluent message id.
70
*/
71
function getRawMessage (id) {
72
  let bundle = fluentBundles[getLocale()]
×
73

74
  if (!bundle.hasMessage(id)) bundle = fluentBundles.en
×
75

76
  if (bundle.hasMessage(id)) return bundle.getMessage(id).value
×
77

78
  return id
×
79
}
80

81
/**
82
* Translate and transform a message pattern
83
* Defaults to en if message id not found in requested locale
84
* @param {string} id - The Fluent message id.
85
* @param {object} args - key/value pairs corresponding to pattern in Fluent resource.
86
* @example
87
* // Given FluentResource("hello = Hello, {$name}!")
88
* getMessage (hello, {name: "Jane"})
89
* // Returns "Hello, Jane!"
90
*/
91
function getMessage (id, args) {
92
  let bundle = fluentBundles[getLocale()]
×
93

94
  if (!bundle.hasMessage(id)) bundle = fluentBundles.en
×
95

96
  if (bundle.hasMessage(id)) return bundle.formatPattern(bundle.getMessage(id).value, args)
×
97

98
  return id
×
99
}
100

101
function fluentError (id) {
102
  return new Error(getMessage(id))
×
103
}
104

105
export { initFluentBundles, updateLocale, getLocale, getMessage, getRawMessage, fluentError }
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc