diff options
author | HiDeoo | 2024-11-04 11:28:50 +0100 |
---|---|---|
committer | GitHub | 2024-11-04 11:28:50 +0100 |
commit | 236467bb745cea7a284ae3d398874d3edbcd846e (patch) | |
tree | 2dd7d22e0c4c9103d45071fd688e088314b91f82 | |
parent | c846696c48b3d21645185a001f00a820bddfc22b (diff) | |
download | IT.starlight-236467bb745cea7a284ae3d398874d3edbcd846e.tar.gz IT.starlight-236467bb745cea7a284ae3d398874d3edbcd846e.tar.bz2 IT.starlight-236467bb745cea7a284ae3d398874d3edbcd846e.zip |
Add YAML support to the FS translation system (#2565)
-rw-r--r-- | .changeset/thick-houses-pull.md | 5 | ||||
-rw-r--r-- | packages/starlight/__tests__/i18n/malformed-json-src/content/i18n/en.json (renamed from packages/starlight/__tests__/i18n/malformed-src/content/i18n/en.json) | 0 | ||||
-rw-r--r-- | packages/starlight/__tests__/i18n/malformed-yaml-src/content/i18n/en.yml | 1 | ||||
-rw-r--r-- | packages/starlight/__tests__/i18n/src/content/i18n/fr.yml | 1 | ||||
-rw-r--r-- | packages/starlight/__tests__/i18n/translations-fs.test.ts | 26 | ||||
-rw-r--r-- | packages/starlight/package.json | 2 | ||||
-rw-r--r-- | packages/starlight/utils/translations-fs.ts | 26 | ||||
-rw-r--r-- | pnpm-lock.yaml | 10 |
8 files changed, 58 insertions, 13 deletions
diff --git a/.changeset/thick-houses-pull.md b/.changeset/thick-houses-pull.md new file mode 100644 index 00000000..69b82f1b --- /dev/null +++ b/.changeset/thick-houses-pull.md @@ -0,0 +1,5 @@ +--- +'@astrojs/starlight': patch +--- + +Fixes an issue with custom UI strings defined in YAML files not being loaded in some contexts. diff --git a/packages/starlight/__tests__/i18n/malformed-src/content/i18n/en.json b/packages/starlight/__tests__/i18n/malformed-json-src/content/i18n/en.json index e69de29b..e69de29b 100644 --- a/packages/starlight/__tests__/i18n/malformed-src/content/i18n/en.json +++ b/packages/starlight/__tests__/i18n/malformed-json-src/content/i18n/en.json diff --git a/packages/starlight/__tests__/i18n/malformed-yaml-src/content/i18n/en.yml b/packages/starlight/__tests__/i18n/malformed-yaml-src/content/i18n/en.yml new file mode 100644 index 00000000..6fa1f172 --- /dev/null +++ b/packages/starlight/__tests__/i18n/malformed-yaml-src/content/i18n/en.yml @@ -0,0 +1 @@ +test: 'Malformed YAML file with dangling trailing comma', diff --git a/packages/starlight/__tests__/i18n/src/content/i18n/fr.yml b/packages/starlight/__tests__/i18n/src/content/i18n/fr.yml new file mode 100644 index 00000000..df8ac1bd --- /dev/null +++ b/packages/starlight/__tests__/i18n/src/content/i18n/fr.yml @@ -0,0 +1 @@ +page.editLink: Rendre cette page différente diff --git a/packages/starlight/__tests__/i18n/translations-fs.test.ts b/packages/starlight/__tests__/i18n/translations-fs.test.ts index 0115f1d3..549d2cb9 100644 --- a/packages/starlight/__tests__/i18n/translations-fs.test.ts +++ b/packages/starlight/__tests__/i18n/translations-fs.test.ts @@ -1,5 +1,6 @@ import { describe, expect, test } from 'vitest'; import { createTranslationSystemFromFs } from '../../utils/translations-fs'; +import { YAMLException } from 'js-yaml'; describe('createTranslationSystemFromFs', () => { test('creates a translation system that returns default strings', () => { @@ -18,14 +19,21 @@ describe('createTranslationSystemFromFs', () => { test('creates a translation system that uses custom strings', () => { const useTranslations = createTranslationSystemFromFs( { - locales: { en: { label: 'English', dir: 'ltr' } }, + locales: { + en: { label: 'English', dir: 'ltr', lang: 'en' }, + fr: { label: 'Français', dir: 'ltr', lang: 'fr' }, + }, defaultLocale: { label: 'English', locale: 'en', dir: 'ltr' }, }, // Using `src/` to load custom files in this test fixture. { srcDir: new URL('./src/', import.meta.url) } ); - const t = useTranslations('en'); + // From an i18n JSON file + let t = useTranslations('en'); expect(t('page.editLink')).toMatchInlineSnapshot('"Make this page different"'); + // From an i18n YAML file + t = useTranslations('fr'); + expect(t('page.editLink')).toMatchInlineSnapshot('"Rendre cette page différente"'); }); test('supports root locale', () => { @@ -68,12 +76,22 @@ describe('createTranslationSystemFromFs', () => { expect(() => createTranslationSystemFromFs( { locales: {}, defaultLocale: { label: 'English', locale: 'en', dir: 'ltr' } }, - // Using `malformed-src/` to trigger syntax error in bad JSON file. - { srcDir: new URL('./malformed-src/', import.meta.url) } + // Using `malformed-json-src/` to trigger syntax error in bad JSON file. + { srcDir: new URL('./malformed-json-src/', import.meta.url) } ) ).toThrow(SyntaxError); }); + test('throws on malformed i18n YAML', () => { + expect(() => + createTranslationSystemFromFs( + { locales: {}, defaultLocale: { label: 'English', locale: 'en', dir: 'ltr' } }, + // Using `malformed-yaml-src/` to trigger syntax error in bad YAML file. + { srcDir: new URL('./malformed-yaml-src/', import.meta.url) } + ) + ).toThrow(YAMLException); + }); + test('creates a translation system that uses custom strings injected by plugins', () => { const useTranslations = createTranslationSystemFromFs( { diff --git a/packages/starlight/package.json b/packages/starlight/package.json index f2c2bc21..f0422afa 100644 --- a/packages/starlight/package.json +++ b/packages/starlight/package.json @@ -177,6 +177,7 @@ "devDependencies": { "@astrojs/markdown-remark": "^5.1.0", "@playwright/test": "^1.45.0", + "@types/js-yaml": "^4.0.9", "@types/node": "^18.16.19", "@vitest/coverage-v8": "^1.6.0", "astro": "^4.15.3", @@ -196,6 +197,7 @@ "hast-util-to-string": "^3.0.0", "hastscript": "^9.0.0", "i18next": "^23.11.5", + "js-yaml": "^4.1.0", "mdast-util-directive": "^3.0.0", "mdast-util-to-markdown": "^2.1.0", "mdast-util-to-string": "^4.0.0", diff --git a/packages/starlight/utils/translations-fs.ts b/packages/starlight/utils/translations-fs.ts index cd927aa5..4bcfcdaa 100644 --- a/packages/starlight/utils/translations-fs.ts +++ b/packages/starlight/utils/translations-fs.ts @@ -1,9 +1,14 @@ import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import yaml from 'js-yaml'; import type { i18nSchemaOutput } from '../schemas/i18n'; import { createTranslationSystem } from './createTranslationSystem'; import type { StarlightConfig } from './user-config'; import type { AstroConfig } from 'astro'; +const contentCollectionFileExtensions = ['.json', '.yaml', '.yml']; + /** * Loads and creates a translation system from the file system. * Only for use in integration code. @@ -23,15 +28,18 @@ export function createTranslationSystemFromFs<T extends i18nSchemaOutput>( // Load the user’s i18n directory const files = fs.readdirSync(i18nDir, 'utf-8'); // Load the user’s i18n collection and ignore the error if it doesn’t exist. - userTranslations = Object.fromEntries( - files - .filter((file) => file.endsWith('.json')) - .map((file) => { - const id = file.slice(0, -5); - const data = JSON.parse(fs.readFileSync(new URL(file, i18nDir), 'utf-8')); - return [id, data] as const; - }) - ); + for (const file of files) { + const filePath = path.parse(file); + if (!contentCollectionFileExtensions.includes(filePath.ext)) continue; + const id = filePath.name; + const url = new URL(filePath.base, i18nDir); + const content = fs.readFileSync(new URL(file, i18nDir), 'utf-8'); + const data = + filePath.ext === '.json' + ? JSON.parse(content) + : yaml.load(content, { filename: fileURLToPath(url) }); + userTranslations[id] = data as i18nSchemaOutput; + } } catch (e: unknown) { if (e instanceof Error && 'code' in e && e.code === 'ENOENT') { // i18nDir doesn’t exist, so we ignore the error. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 556e52ec..d95a2f9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -197,6 +197,9 @@ importers: i18next: specifier: ^23.11.5 version: 23.11.5 + js-yaml: + specifier: ^4.1.0 + version: 4.1.0 mdast-util-directive: specifier: ^3.0.0 version: 3.0.0 @@ -234,6 +237,9 @@ importers: '@playwright/test': specifier: ^1.45.0 version: 1.45.0 + '@types/js-yaml': + specifier: ^4.0.9 + version: 4.0.9 '@types/node': specifier: ^18.16.19 version: 18.16.19 @@ -1997,6 +2003,10 @@ packages: dependencies: '@types/unist': 3.0.0 + /@types/js-yaml@4.0.9: + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + dev: true + /@types/linkify-it@5.0.0: resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} requiresBuild: true |