aboutsummaryrefslogtreecommitdiff
path: root/test/locale-data.spec.ts
blob: e5d7e1e4d2d6046b7ad87d8c3347b67ac0f59e92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import { describe, expect, it } from 'vitest';
import { allLocales } from '../src';
import './vitest-extensions';

function checkLocaleData(data: unknown) {
  if (Array.isArray(data)) {
    it('should not have duplicate entries', () => {
      expect(data).not.toContainDuplicates();
    });
  } else if (typeof data === 'object' && data != null) {
    describe.each(Object.entries(data))('%s', (_, nestedData) => {
      checkLocaleData(nestedData);
    });
  } else {
    it.skip('primitives cannot be tested');
  }
}

/**
 * A set of locale data paths that should be ignored when checking for characters.
 * Because these usually contain data using Latin characters that are otherwise not relevant to the locale.
 */
const ignoredCharacterData = new Set([
  '.airline.airline[].iataCode',
  '.airline.airplane[].iataTypeCode',
  '.airline.airport[].iataCode',
  '.finance.currency',
  '.finance.credit_card',
  '.hacker.abbreviation',
  '.internet.domain_suffix',
  '.internet.emoji',
  '.internet.example_email',
  '.internet.free_email',
  '.location.country_code',
  '.metadata',
  '.science.chemical_element[].symbol',
  '.science.unit[].symbol',
  '.system.directory_path',
  '.system.mime_type',
]);

function uniqueCharacters(data: string | string[]): string[] {
  return [...new Set(data)];
}

function allCharacters(data: unknown, path: string = ''): string[] {
  if (ignoredCharacterData.has(path)) {
    return [];
  } else if (Array.isArray(data)) {
    return uniqueCharacters(data.flatMap((e) => allCharacters(e, `${path}[]`)));
  } else if (typeof data === 'object' && data != null) {
    return uniqueCharacters(
      Object.entries(data).flatMap(([key, entry]) =>
        allCharacters(entry, `${path}.${key}`)
      )
    );
  } else if (typeof data === 'string') {
    return uniqueCharacters(
      data
        .replaceAll(/{{(?:[^{]|{(?!{))*?}}/g, '') // remove placeholders
        .replaceAll(/\d+/g, '') // remove numbers
    );
  }

  return [];
}

describe('locale-data', () => {
  checkLocaleData(allLocales);

  // This test exists to keep track of the characters used in each locale.
  // It doesn't matter if new characters are added as long as they belong to that language.
  it('should only have known characters', () => {
    const characterSets = Object.fromEntries(
      Object.entries(allLocales).map(([locale, data]) => [
        locale,
        allCharacters(data).sort().join(''),
      ])
    );
    expect(characterSets).toMatchSnapshot();
  });
});