@playpilot/tpi 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,238 @@
1
+ import { Language } from '$lib/enums/Language.js'
2
+
3
+ export const translations = {
4
+ 'Where To Stream Online': {
5
+ [Language.English]: 'Where to stream online',
6
+ [Language.Swedish]: 'Var kan man streama online',
7
+ },
8
+ 'Affiliate Disclaimer': {
9
+ [Language.English]: 'We may earn a commission if you make a purchase through these links. In collaboration with',
10
+ [Language.Swedish]: 'Vi kan få provision om du gör ett köp via dessa länkar. I samarbete med',
11
+ },
12
+ 'An Error Occurred': {
13
+ [Language.English]: 'An error occurred',
14
+ [Language.Swedish]: 'Ett fel inträffade',
15
+ },
16
+ 'Title Unavailable': {
17
+ [Language.English]: 'This title is not currently available to stream.',
18
+ [Language.Swedish]: 'Den här titeln går inte att streama just nu.',
19
+ },
20
+ 'Title Unavailable Suffix': {
21
+ [Language.English]: 'is not currently available to stream.',
22
+ [Language.Swedish]: 'går inte att streama just nu.',
23
+ },
24
+ 'Is Available To Stream On': {
25
+ [Language.English]: 'is available to stream on',
26
+ [Language.Swedish]: 'finns att streama på',
27
+ },
28
+ 'Is Available To Stream': {
29
+ [Language.English]: 'is available to stream.',
30
+ [Language.Swedish]: 'finns att streama.',
31
+ },
32
+ 'View Streaming Options': {
33
+ [Language.English]: 'View streaming options',
34
+ [Language.Swedish]: 'Se streamingalternativ',
35
+ },
36
+ 'And': {
37
+ [Language.English]: 'and',
38
+ [Language.Swedish]: 'och',
39
+ },
40
+ 'Minutes': {
41
+ [Language.English]: 'minutes',
42
+ [Language.Swedish]: 'minuter',
43
+ },
44
+ 'Type: movie': {
45
+ [Language.English]: 'Movie',
46
+ [Language.Swedish]: 'Film',
47
+ },
48
+ 'Type: series': {
49
+ [Language.English]: 'Series',
50
+ [Language.Swedish]: 'Serie',
51
+ },
52
+ 'Stream': {
53
+ [Language.English]: 'Stream',
54
+ [Language.Swedish]: 'Strömma',
55
+ },
56
+ 'Buy': {
57
+ [Language.English]: 'Buy',
58
+ [Language.Swedish]: 'Köp',
59
+ },
60
+ 'Rent': {
61
+ [Language.English]: 'Rent',
62
+ [Language.Swedish]: 'Hyra',
63
+ },
64
+ 'Rent Or Buy': {
65
+ [Language.English]: 'Rent or Buy',
66
+ [Language.Swedish]: 'Hyra',
67
+ },
68
+
69
+ // Genres
70
+ 'All': {
71
+ [Language.English]: 'All',
72
+ [Language.Swedish]: 'Alla',
73
+ },
74
+ 'Unscripted': {
75
+ [Language.English]: 'Unscripted',
76
+ [Language.Swedish]: 'Oscripterat',
77
+ },
78
+ 'Independent': {
79
+ [Language.English]: 'Independent',
80
+ [Language.Swedish]: 'Indie',
81
+ },
82
+ 'Game Show': {
83
+ [Language.English]: 'Game Show',
84
+ [Language.Swedish]: 'Gameshow',
85
+ },
86
+ 'Film Noir': {
87
+ [Language.English]: 'Film Noir',
88
+ [Language.Swedish]: 'Film noir',
89
+ },
90
+ 'Entertainment': {
91
+ [Language.English]: 'Entertainment',
92
+ [Language.Swedish]: 'Underhållning',
93
+ },
94
+ 'News': {
95
+ [Language.English]: 'News',
96
+ [Language.Swedish]: 'Nyheter',
97
+ },
98
+ 'Short': {
99
+ [Language.English]: 'Short',
100
+ [Language.Swedish]: 'Kortfilm',
101
+ },
102
+ 'Bollywood': {
103
+ [Language.English]: 'Bollywood',
104
+ [Language.Swedish]: 'Bollywood',
105
+ },
106
+ 'Concert': {
107
+ [Language.English]: 'Concert',
108
+ [Language.Swedish]: 'Konsert',
109
+ },
110
+ 'Arthouse': {
111
+ [Language.English]: 'Arthouse',
112
+ [Language.Swedish]: 'Arthouse',
113
+ },
114
+ 'Alternate Version': {
115
+ [Language.English]: 'Alternate Version',
116
+ [Language.Swedish]: 'Alternativ version',
117
+ },
118
+ 'Reality TV': {
119
+ [Language.English]: 'Reality TV',
120
+ [Language.Swedish]: 'Reality-TV',
121
+ },
122
+ 'Culture': {
123
+ [Language.English]: 'Culture',
124
+ [Language.Swedish]: 'Kultur',
125
+ },
126
+ 'Drama': {
127
+ [Language.English]: 'Drama',
128
+ [Language.Swedish]: 'Drama',
129
+ },
130
+ 'Crime': {
131
+ [Language.English]: 'Crime',
132
+ [Language.Swedish]: 'Kriminal',
133
+ },
134
+ 'Western': {
135
+ [Language.English]: 'Western',
136
+ [Language.Swedish]: 'Western',
137
+ },
138
+ 'Thriller': {
139
+ [Language.English]: 'Thriller',
140
+ [Language.Swedish]: 'Thriller',
141
+ },
142
+ 'Animation': {
143
+ [Language.English]: 'Animation',
144
+ [Language.Swedish]: 'Animerat',
145
+ },
146
+ 'Mystery': {
147
+ [Language.English]: 'Mystery',
148
+ [Language.Swedish]: 'Mysterium',
149
+ },
150
+ 'Science': {
151
+ [Language.English]: 'Science',
152
+ [Language.Swedish]: 'Vetenskap',
153
+ },
154
+ 'Nature': {
155
+ [Language.English]: 'Nature',
156
+ [Language.Swedish]: 'Natur',
157
+ },
158
+ 'War': {
159
+ [Language.English]: 'War',
160
+ [Language.Swedish]: 'Krig',
161
+ },
162
+ 'Sci-Fi': {
163
+ [Language.English]: 'Sci-Fi',
164
+ [Language.Swedish]: 'Sci-fi',
165
+ },
166
+ 'Documentary': {
167
+ [Language.English]: 'Documentary',
168
+ [Language.Swedish]: 'Dokumentär',
169
+ },
170
+ 'Stand-up': {
171
+ [Language.English]: 'Stand-up',
172
+ [Language.Swedish]: 'Standup',
173
+ },
174
+ 'Talk Show': {
175
+ [Language.English]: 'Talk Show',
176
+ [Language.Swedish]: 'Talkshow',
177
+ },
178
+ 'Fantasy': {
179
+ [Language.English]: 'Fantasy',
180
+ [Language.Swedish]: 'Fantasy',
181
+ },
182
+ 'History': {
183
+ [Language.English]: 'History',
184
+ [Language.Swedish]: 'Historia',
185
+ },
186
+ 'Adventure': {
187
+ [Language.English]: 'Adventure',
188
+ [Language.Swedish]: 'Äventyr',
189
+ },
190
+ 'Action': {
191
+ [Language.English]: 'Action',
192
+ [Language.Swedish]: 'Action',
193
+ },
194
+ 'Horror': {
195
+ [Language.English]: 'Horror',
196
+ [Language.Swedish]: 'Skräck',
197
+ },
198
+ 'Comedy': {
199
+ [Language.English]: 'Comedy',
200
+ [Language.Swedish]: 'Komedi',
201
+ },
202
+ 'Biography': {
203
+ [Language.English]: 'Biography',
204
+ [Language.Swedish]: 'Biografi',
205
+ },
206
+ 'Music': {
207
+ [Language.English]: 'Music',
208
+ [Language.Swedish]: 'Musik',
209
+ },
210
+ 'Sport': {
211
+ [Language.English]: 'Sport',
212
+ [Language.Swedish]: 'Sport',
213
+ },
214
+ 'Romance': {
215
+ [Language.English]: 'Romance',
216
+ [Language.Swedish]: 'Romantik',
217
+ },
218
+ 'Kids': {
219
+ [Language.English]: 'Kids',
220
+ [Language.Swedish]: 'Barn',
221
+ },
222
+ 'Lifestyle': {
223
+ [Language.English]: 'Lifestyle',
224
+ [Language.Swedish]: 'Livsstil',
225
+ },
226
+ 'Musical': {
227
+ [Language.English]: 'Musical',
228
+ [Language.Swedish]: 'Musikal',
229
+ },
230
+ 'Anime': {
231
+ [Language.English]: 'Anime',
232
+ [Language.Swedish]: 'Anime',
233
+ },
234
+ 'Family': {
235
+ [Language.English]: 'Family',
236
+ [Language.Swedish]: 'Familj',
237
+ },
238
+ }
@@ -0,0 +1,4 @@
1
+ export const Language = Object.freeze({
2
+ English: 'en-US',
3
+ Swedish: 'sv-SE',
4
+ })
@@ -0,0 +1,36 @@
1
+ import { translations } from '$lib/data/translations'
2
+ import { Language } from '$lib/enums/Language'
3
+
4
+ /**
5
+ * Super basic implementation to get a string for the given key and language
6
+ * @param {string} key Key of the wanted translation
7
+ * @param {LanguageCode} language Language code
8
+ * @returns
9
+ */
10
+ export function t(key, language = getLanguage()) {
11
+ // @ts-ignore It's ok if a key is not found.
12
+ return translations[key]?.[language] || key
13
+ }
14
+
15
+ /**
16
+ * @returns {LanguageCode}
17
+ */
18
+ export function getLanguage() {
19
+ // @ts-ignore
20
+ const configLanguage = window.PlayPilotLinkInjections?.language
21
+ const languageCodes = /** @type {string[]} */ (Object.values(Language))
22
+
23
+ if (configLanguage) {
24
+ if (languageCodes.includes(configLanguage)) return configLanguage
25
+
26
+ console.warn(`PlayPilot Link Injections: ${configLanguage} is not an accepted language`)
27
+ }
28
+
29
+ const documentLanguage = document.querySelector('html')?.getAttribute('lang')
30
+
31
+ if (documentLanguage && languageCodes.includes(documentLanguage)) {
32
+ return /** @type {LanguageCode} */ (documentLanguage)
33
+ }
34
+
35
+ return Language.English
36
+ }
@@ -0,0 +1,82 @@
1
+ import { getLinkInjectionsParentElement } from './linkInjection'
2
+
3
+ /**
4
+ * Returns meta data to be included with injections.
5
+ * @returns {ArticleMetaData}
6
+ */
7
+ export function getPageMetaData() {
8
+ const parent = getLinkInjectionsParentElement()
9
+
10
+ return {
11
+ heading: getPageHeading(parent),
12
+ modified_time: getPageModifiedTime(parent),
13
+ published_time: getPageModifiedTime(parent),
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Returns the most relevant `h1` content on the page.
19
+ * A page should only ever contain exactly 1 `h1` tag, but we don't control these things.
20
+ * @param {HTMLElement} parent
21
+ * @returns {string | null}
22
+ */
23
+ export function getPageHeading(parent) {
24
+ const heading = parent.querySelector('h1') || document.querySelector('h1')
25
+
26
+ return heading?.innerText.trim() || null
27
+ }
28
+
29
+ /**
30
+ * Returns the datetime for the article, intended to be the last time the article was modified.
31
+ * @param {HTMLElement} parent
32
+ * @returns {string | null}
33
+ */
34
+ export function getPageModifiedTime(parent) {
35
+ const element =
36
+ /** @type {HTMLElement | null} */
37
+ (document.querySelector('meta[property*="modified_time"]') ||
38
+ parent.querySelector('[itemprop="dateModified"]') ||
39
+ document.querySelector('[itemprop="dateModified"]') || null)
40
+
41
+ const datetime = element?.getAttribute('content') || element?.getAttribute('datetime') || element?.innerText
42
+
43
+ if (!datetime) return null
44
+
45
+ return getDatetime(datetime)
46
+ }
47
+
48
+ /**
49
+ * Returns the datetime for the article, intended to be the date the article was first published
50
+ * @param {HTMLElement} parent
51
+ * @returns {string | null}
52
+ */
53
+ export function getPagePublishedTime(parent) {
54
+ const element =
55
+ /** @type {HTMLElement | null} */
56
+ (document.querySelector('meta[property*="published_time"]') ||
57
+ parent.querySelector('[itemprop="datePublished"]') ||
58
+ document.querySelector('[itemprop="datePublished"]') ||
59
+ parent.querySelector('time') ||
60
+ document.querySelector('time') ||
61
+ parent.querySelector('[datetime]') ||
62
+ document.querySelector('[datetime]') || null)
63
+
64
+ const datetime = element?.getAttribute('content') || element?.getAttribute('datetime') || element?.innerText
65
+
66
+ if (!datetime) return null
67
+
68
+ return getDatetime(datetime)
69
+ }
70
+
71
+ /**
72
+ * Get datetime string as ISO datetime string
73
+ * @param {string} datetime
74
+ * @returns {string | null}
75
+ */
76
+ function getDatetime(datetime) {
77
+ try {
78
+ return new Date(datetime).toISOString()
79
+ } catch {
80
+ return null
81
+ }
82
+ }
package/src/main.js CHANGED
@@ -8,9 +8,10 @@ window.PlayPilotLinkInjections = {
8
8
  token: '',
9
9
  editorial_token: '',
10
10
  selector: '',
11
+ language: null,
11
12
  app: null,
12
13
 
13
- initialize(config = { token: '', selector: '', editorial_token: '' }) {
14
+ initialize(config = { token: '', selector: '', language: null, editorial_token: '' }) {
14
15
  if (!config.token) {
15
16
  console.error('An API token is required.')
16
17
  return
@@ -19,6 +20,7 @@ window.PlayPilotLinkInjections = {
19
20
  this.token = config.token
20
21
  this.editorial_token = config.editorial_token
21
22
  this.selector = config.selector
23
+ this.language = config.language
22
24
 
23
25
  if (this.app) this.destroy()
24
26
 
@@ -22,6 +22,8 @@
22
22
  <div>
23
23
  {#key Math.random()}
24
24
  <article use:noClass>
25
+ <h1 use:noClass>Some heading</h1>
26
+ <time datetime="13:00">1 hour ago</time>
25
27
  <p use:noClass>Following the success of John M. Chu's 2018 romantic-comedy Crazy Rich Asians, Quan was inspired to return to acting. He first scored a supporting role in the Netflix movie Finding 'Ohana, before securing a starring role in the absurdist comedy-drama Everything Everywhere all At Once. A critical and commercial success, the film earned $143 million against a budget of $14-25 million, and saw Quan win the Academy Award for Best Supporting Actor. Following his win, Quan struggled to choose projects he was satisfied with, passing on an action-comedy three times, before finally taking his first leading role in it, following advice from Spielberg.</p>
26
28
  <p use:noClass>In an interview with Epire &amp; Magazine, Quan reveals he quested starring in Love Hurts, which sees him in the leading role of a former assassin turned successful realtor, whose past returns when his brother attempts to hunt him down. The movie is in a similar vein to successful films such as The Long Kiss Goodnight and Nobody, and Quan discussed how he was reluctant to take the part due to his conditioned beliefs about how an action hero should look. But he reveals that he changed his mind following a meeting with Spielberg, who convinced him to do it.</p>
27
29
  </article>
@@ -1,5 +1,6 @@
1
1
  <script>
2
2
  import { TrackingEvent } from '$lib/enums/TrackingEvent'
3
+ import { t } from '$lib/localization'
3
4
  import { track } from '$lib/tracking'
4
5
 
5
6
  /** @type {{ linkInjections: LinkInjection[], onclickmodal?: (linkInjection: LinkInjection) => void }} */
@@ -34,18 +35,18 @@
34
35
  <span data-playpilot-injection-key={key}>
35
36
  {#if playlinks.length}
36
37
  {#if after_article_style === 'modal_button'}
37
- "{title}" is available to stream.
38
+ "{title}" {t('Is Available To Stream')}
38
39
 
39
40
  <span>
40
41
  <button onclick={() => openModal(/** @type {TitleData} */ (title_details), linkInjection)}>
41
- View streaming options
42
+ {t('View Streaming Options')}
42
43
  </button>
43
44
  </span>
44
45
  {:else}
45
- "{title}" is available to stream on
46
+ "{title}" {t('Is Available To Stream On')}
46
47
  {#each playlinks as { name, url }, i}
47
48
  {#if i}
48
- {i === playlinks.length - 1 ? ', and' : ','}
49
+ {i === playlinks.length - 1 ? `, ${t('And')}` : ','}
49
50
  {/if}
50
51
 
51
52
  <a onclick={() => onclick(/** @type {TitleData} */ (title_details), name)} href={url} target="_blank">
@@ -55,7 +56,7 @@
55
56
  {/if}
56
57
  <br>
57
58
  {:else}
58
- "{title}" is not currently available to stream. <br>
59
+ "{title}" {t('Title Unavailable Suffix')} <br>
59
60
  {/if}
60
61
  </span>
61
62
  {/each}
@@ -160,7 +160,7 @@
160
160
  }
161
161
 
162
162
  .editor {
163
- z-index: 1000;
163
+ z-index: 2147483646; // 1 less than as high as she goes;
164
164
  display: flex;
165
165
  flex-direction: column;
166
166
  position: fixed;
@@ -1,5 +1,6 @@
1
1
  <script>
2
2
  import genreData from '$lib/genres.json'
3
+ import { t } from '$lib/localization'
3
4
 
4
5
  /** @type {{ genres: string[] }} */
5
6
  const { genres } = $props()
@@ -9,9 +10,13 @@
9
10
  </script>
10
11
 
11
12
  {#each shownGenres as genre}
12
- <div class="genre">
13
- {genreData.find(g => g.slug === genre)?.name}
14
- </div>
13
+ {@const genreName = genreData.find(g => g.slug === genre)?.name}
14
+
15
+ {#if genreName}
16
+ <div class="genre">
17
+ {t(genreName)}
18
+ </div>
19
+ {/if}
15
20
  {/each}
16
21
 
17
22
  {#if !expanded && genres.length > 1}
@@ -48,7 +48,7 @@
48
48
 
49
49
  <style lang="scss">
50
50
  .modal {
51
- z-index: 9999;
51
+ z-index: 2147483647; // As high as she goes
52
52
  position: fixed;
53
53
  display: flex;
54
54
  justify-content: center;
@@ -1,5 +1,6 @@
1
1
  <script>
2
2
  import { TrackingEvent } from '$lib/enums/TrackingEvent'
3
+ import { t } from '$lib/localization'
3
4
  import { mergePlaylinks } from '$lib/playlink'
4
5
  import { track } from '$lib/tracking'
5
6
  import IconContinue from './Icons/IconContinue.svelte'
@@ -15,10 +16,10 @@
15
16
  const mergedPlaylink = $derived(mergePlaylinks(filteredPlaylinks))
16
17
 
17
18
  const categoryStrings = {
18
- SVOD: 'Stream',
19
- BUY: 'Buy',
20
- RENT: 'Rent',
21
- TVOD: 'Rent or Buy',
19
+ SVOD: t('Stream'),
20
+ BUY: t('Buy'),
21
+ RENT: t('Rent'),
22
+ TVOD: t('Rent Or Buy'),
22
23
  }
23
24
 
24
25
  /**
@@ -29,7 +30,7 @@
29
30
  }
30
31
  </script>
31
32
 
32
- <h2>Where to stream online</h2>
33
+ <h2>{t('Where To Stream Online')}</h2>
33
34
 
34
35
  <div class="playlinks" class:list>
35
36
  {#each mergedPlaylink as { name, url, logo_url, extra_info: { category } }}
@@ -38,7 +39,7 @@
38
39
 
39
40
  <div>
40
41
  <span class="name">{name}</span>
41
- <div class="category">{categoryStrings[category] || 'Stream'}</div>
42
+ <div class="category">{categoryStrings[category] || t('Stream')}</div>
42
43
  </div>
43
44
 
44
45
  {#if list}
@@ -51,7 +52,7 @@
51
52
 
52
53
  {#if !playlinks.length}
53
54
  <div class="playlink empty">
54
- This title is not currently available to stream. Save it and we'll notify you when it's available.
55
+ {t('Title Unavailable')}
55
56
  </div>
56
57
  {/if}
57
58
  </div>
@@ -73,7 +73,7 @@
73
73
  max-width: margin(20);
74
74
  padding: var(--offset) 0;
75
75
  transform: translateY(calc(-100% + var(--offset)));
76
- z-index: 999;
76
+ z-index: 2147483647; // As high as she goes
77
77
 
78
78
  &.flip {
79
79
  top: auto;
@@ -4,6 +4,7 @@
4
4
  import Description from './Description.svelte'
5
5
  import Participants from './Participants.svelte'
6
6
  import IconIMDb from './Icons/IconIMDb.svelte'
7
+ import { t } from '$lib/localization'
7
8
 
8
9
  /** @type {{ title: TitleData, small?: boolean, compact?: boolean }} */
9
10
  const { title, small = false, compact = false } = $props()
@@ -28,10 +29,10 @@
28
29
  <Genres genres={title.genres} />
29
30
 
30
31
  <div>{title.year}</div>
31
- <div class="capitalize">{title.type}</div>
32
+ <div class="capitalize">{t(`Type: ${title.type}`)}</div>
32
33
 
33
34
  {#if title.length}
34
- <div>{title.length} minutes</div>
35
+ <div>{title.length} {t('Minutes')}</div>
35
36
  {/if}
36
37
  </div>
37
38
  </header>
@@ -38,6 +38,11 @@ describe('$lib/api', () => {
38
38
  body: JSON.stringify({
39
39
  hash: 'some-hash',
40
40
  url: 'https://some-url',
41
+ metadata: {
42
+ heading: null,
43
+ modified_time: null,
44
+ published_time: null,
45
+ },
41
46
  page_text: 'some-html',
42
47
  }),
43
48
  method: 'POST',
@@ -0,0 +1,67 @@
1
+ import { describe, it, expect, afterEach } from 'vitest'
2
+ import { getLanguage, t } from '$lib/localization'
3
+ import { Language } from '$lib/enums/Language'
4
+ import { translations } from '$lib/data/translations'
5
+
6
+ describe('localization.js', () => {
7
+ describe('t', () => {
8
+ it('Should return the value for the given language and key', () => {
9
+ expect(t(Object.keys(translations)[0], Language.English)).toBe(Object.values(translations)[0][Language.English])
10
+ expect(t(Object.keys(translations)[0], Language.Swedish)).toBe(Object.values(translations)[0][Language.Swedish])
11
+ })
12
+
13
+ it('Should return the key if key is not found in the object', () => {
14
+ expect(t('Some Random Key')).toBe('Some Random Key')
15
+ })
16
+
17
+ it('Should return the key if key is not found for the given language', () => {
18
+ // @ts-ignore
19
+ expect(t(Object.keys(translations)[0], 'Some Invalid Language')).toBe(Object.keys(translations)[0])
20
+ })
21
+ })
22
+
23
+ describe('getLanguage', () => {
24
+ afterEach(() => {
25
+ // @ts-expect-error
26
+ window.PlayPilotLinkInjections = {}
27
+ })
28
+
29
+ it('Should return the language given in config object before document language', () => {
30
+ // @ts-expect-error
31
+ window.PlayPilotLinkInjections = { language: 'sv-SE' }
32
+
33
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
34
+ html.setAttribute('lang', 'en-US')
35
+
36
+ expect(getLanguage()).toBe('sv-SE')
37
+ })
38
+
39
+ it('Should return the language given as document language when config language is invalid', () => {
40
+ // @ts-expect-error
41
+ window.PlayPilotLinkInjections = { language: 'no' }
42
+
43
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
44
+ html.setAttribute('lang', 'sv-SE')
45
+
46
+ expect(getLanguage()).toBe('sv-SE')
47
+ })
48
+
49
+ it('Should return the language given as document language when no config object is set', () => {
50
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
51
+ html.setAttribute('lang', 'sv-SE')
52
+
53
+ expect(getLanguage()).toBe('sv-SE')
54
+ })
55
+
56
+ it('Should return the default language when document language is invalid', () => {
57
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
58
+ html.setAttribute('lang', 'no')
59
+
60
+ expect(getLanguage()).toBe('en-US')
61
+ })
62
+
63
+ it('Should return the default language no document language or config language is given', () => {
64
+ expect(getLanguage()).toBe('en-US')
65
+ })
66
+ })
67
+ })