summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiDeoo2024-06-09 20:04:12 +0200
committerGitHub2024-06-09 20:04:12 +0200
commit0b8a843936bd8506ac228608b07c54a76a7add19 (patch)
treeab374a11d0f0c220a7b77bba7eda46722d01d00f
parente6c0467100eaa76515d6dd1ee7485a457143f47a (diff)
downloadIT.starlight-0b8a843936bd8506ac228608b07c54a76a7add19.tar.gz
IT.starlight-0b8a843936bd8506ac228608b07c54a76a7add19.tar.bz2
IT.starlight-0b8a843936bd8506ac228608b07c54a76a7add19.zip
Improve locale text direction detection mechanism (#1987)
Co-authored-by: Chris Swithinbank <357379+delucis@users.noreply.github.com>
-rw-r--r--.changeset/olive-oranges-poke.md5
-rw-r--r--packages/starlight/__tests__/basics/i18n.test.ts50
-rw-r--r--packages/starlight/utils/i18n.ts29
3 files changed, 81 insertions, 3 deletions
diff --git a/.changeset/olive-oranges-poke.md b/.changeset/olive-oranges-poke.md
new file mode 100644
index 00000000..f9b1c2d8
--- /dev/null
+++ b/.changeset/olive-oranges-poke.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight': patch
+---
+
+Fixes issues with the locale text direction detection mechanism in some environments like WebContainers or Bun.
diff --git a/packages/starlight/__tests__/basics/i18n.test.ts b/packages/starlight/__tests__/basics/i18n.test.ts
index f609e528..527783b9 100644
--- a/packages/starlight/__tests__/basics/i18n.test.ts
+++ b/packages/starlight/__tests__/basics/i18n.test.ts
@@ -1,4 +1,4 @@
-import { assert, describe, expect, test } from 'vitest';
+import { assert, describe, expect, test, vi } from 'vitest';
import config from 'virtual:starlight/user-config';
import { processI18nConfig, pickLang } from '../../utils/i18n';
import type { AstroConfig } from 'astro';
@@ -250,6 +250,54 @@ describe('processI18nConfig', () => {
});
});
+describe('getLocaleDir', () => {
+ test('uses the Node.js implementation to figure out the text direction', () => {
+ const { starlightConfig } = processI18nConfig(
+ config,
+ getAstroI18nTestConfig({
+ defaultLocale: 'en',
+ locales: ['en'],
+ })
+ );
+
+ expect(starlightConfig.defaultLocale.dir).toBe('ltr');
+ });
+
+ test('uses `getTextInfo()` when `textInfo` is not available', async () => {
+ // @ts-expect-error - `getTextInfo` is not typed but is available in some non-v8 based environments.
+ vi.spyOn(global.Intl, 'Locale').mockImplementation(() => ({
+ getTextInfo: () => ({ direction: 'rtl' }),
+ }));
+
+ const { starlightConfig } = processI18nConfig(
+ config,
+ getAstroI18nTestConfig({
+ defaultLocale: 'en',
+ locales: ['en'],
+ })
+ );
+
+ expect(starlightConfig.defaultLocale.dir).toBe('rtl');
+ });
+
+ test('fallbacks to a list of well-known RTL languages when `textInfo` and `getTextInfo()` are not available', async () => {
+ // @ts-expect-error - We are simulating the absence of `textInfo` and `getTextInfo()`.
+ vi.spyOn(global.Intl, 'Locale').mockImplementation((tag) => ({ language: tag }));
+
+ const { starlightConfig } = processI18nConfig(
+ config,
+ getAstroI18nTestConfig({
+ defaultLocale: 'en',
+ locales: ['en', 'fa'],
+ })
+ );
+
+ expect(starlightConfig.defaultLocale.dir).toBe('ltr');
+ expect(starlightConfig.locales?.root?.dir).toBe('ltr');
+ expect(starlightConfig.locales?.fa?.dir).toBe('rtl');
+ });
+});
+
function getAstroI18nTestConfig(i18nConfig: AstroUserConfig['i18n']): AstroConfig['i18n'] {
return {
...i18nConfig,
diff --git a/packages/starlight/utils/i18n.ts b/packages/starlight/utils/i18n.ts
index cb7c052a..be334ecb 100644
--- a/packages/starlight/utils/i18n.ts
+++ b/packages/starlight/utils/i18n.ts
@@ -6,6 +6,15 @@ import type { StarlightConfig } from './user-config';
export const BuiltInDefaultLocale = { ...getLocaleInfo('en'), lang: 'en' };
/**
+ * A list of well-known right-to-left languages used as a fallback when determining the text
+ * direction of a locale is not supported by the `Intl.Locale` API in the current environment.
+ *
+ * @see getLocaleDir()
+ * @see https://en.wikipedia.org/wiki/IETF_language_tag#List_of_common_primary_language_subtags
+ */
+const wellKnownRTL = ['ar', 'fa', 'he', 'prs', 'ps', 'syc', 'ug', 'ur'];
+
+/**
* Processes the Astro and Starlight i18n configurations to generate/update them accordingly:
*
* - If no Astro and Starlight i18n configurations are provided, the built-in default locale is
@@ -150,8 +159,7 @@ function getLocaleInfo(lang: string) {
if (!label || lang === label) throw new Error('Label not found.');
return {
label: label[0]?.toLocaleUpperCase(locale) + label.slice(1),
- // @ts-expect-error - `textInfo` is not part of the `Intl.Locale` type but is available in Node.js 18.0.0+.
- dir: locale.textInfo.direction as 'ltr' | 'rtl',
+ dir: getLocaleDir(locale),
};
} catch (error) {
throw new AstroError(
@@ -162,6 +170,23 @@ function getLocaleInfo(lang: string) {
}
/**
+ * Returns the direction of the passed locale.
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTextInfo
+ */
+function getLocaleDir(locale: Intl.Locale): 'ltr' | 'rtl' {
+ if ('textInfo' in locale) {
+ // @ts-expect-error - `textInfo` is not typed but is available in v8 based environments.
+ return locale.textInfo.direction;
+ } else if ('getTextInfo' in locale) {
+ // @ts-expect-error - `getTextInfo` is not typed but is available in some non-v8 based environments.
+ return locale.getTextInfo().direction;
+ }
+ // Firefox does not support `textInfo` or `getTextInfo` yet so we fallback to a well-known list
+ // of right-to-left languages.
+ return wellKnownRTL.includes(locale.language) ? 'rtl' : 'ltr';
+}
+
+/**
* Get the string for the passed language from a dictionary object.
*
* TODO: Make this clever. Currently a simple key look-up, but should use