import { readFileSync } from 'node:fs' import { join } from 'node:path' import { describe, expect, it } from 'vitest' import { articleListMessages } from './articleListMessages' import { messages } from './messages' const SOURCES = [ 'components/ArticleFilterBar.vue', 'components/ArticleFilterChips.vue', 'components/ArticleFilterFields.vue', 'components/ArticleFiltersSheet.vue', 'components/ArticleListEmpty.vue', 'components/ArticleListFailure.vue', 'components/ArticleListTabs.vue', 'components/StoryCardList.vue', 'components/StoryCoverage.vue', 'components/StoryRowMenu.vue', 'components/StoryTable.vue', 'lib/articleFilterChips.ts', 'lib/storyList.ts', 'lib/storyMenu.ts', 'views/ArticleView.vue', ] const SAME_IN_FRENCH = new Set([ 'SEO', 'Site', 'Article', 'Articles', 'Actions', '1 version', '{0} versions', '1 article', '{0} articles', ]) const LITERAL = /\bt\(\s*(?:'((?:\\.|[^'\\])*)'|"((?:\\.|[^"\\])*)")/g const NUMBERED = /\{\d+\}/g function keysIn(source: string) { return [...source.matchAll(LITERAL)].map((match) => (match[1] ?? match[2] ?? '').replace(/\\(['"\\])/g, '$1'), ) } describe('Article list messages', () => { const keys = SOURCES.flatMap((file) => keysIn(readFileSync(join(import.meta.dirname, '..', file), 'utf8')).map((key) => ({ file, key, })), ) it('finds the strings of the list screen', () => { expect(keys.length).toBeGreaterThan(60) }) it.each(keys.map(({ file, key }) => [file, key]))( '%s: "%s" has a French entry', (_file, key) => { const french = (messages as Record)[key as string] expect(french).toMatch(/\S/) if (!SAME_IN_FRENCH.has(key as string)) { expect(french).not.toBe(key) } }, ) it.each(Object.entries(articleListMessages))( 'keeps the placeholders of "%s" in French', (english, french) => { expect([...french.matchAll(NUMBERED)].map((m) => m[0]).sort()).toEqual( [...english.matchAll(NUMBERED)].map((m) => m[0]).sort(), ) }, ) })