Skip to content

Commit

Permalink
feat: add locale page
Browse files Browse the repository at this point in the history
  • Loading branch information
jesperorb committed Apr 4, 2024
1 parent 54b695b commit ad6ad05
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 39 deletions.
1 change: 1 addition & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"no": "No",
"noSupport": "No support",
"notAvailableInBrowser": "Not available in {browserName}",
"noValue": "No value",
"options": "Options",
"output": "Output",
"partialSupport": "Partial support",
Expand Down
1 change: 1 addition & 0 deletions messages/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"no": "Nej",
"noSupport": "Inget stöd",
"notAvailableInBrowser": "Inte tillgänglig i {browserName}",
"noValue": "Inget värde",
"options": "Alternativ",
"output": "Utdata",
"partialSupport": "Delvist stöd",
Expand Down
60 changes: 60 additions & 0 deletions src/lib/components/pages/Locale.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script lang="ts">
import CodeBlock from '$lib/components/ui/CodeBlock.svelte';
import Grid from '$lib/components/ui/Grid.svelte';
import Input from '$lib/components/ui/Input.svelte';
import HighlightValue from '$lib/components/ui/HighlightValue.svelte';
import OptionSection from '$lib/components/ui/OptionSection.svelte';
import PageLayout from '$lib/components/pages/PageLayout.svelte';
import { getMessages } from '$lib/i18n/util';
import type { BrowserSupportDataForMethod } from '$lib/types/BrowserSupport.types';
export let browserCompatData: BrowserSupportDataForMethod | null;
const fallback = 'ja-Jpan-JP-u-ca-japanese-hc-h12-kf-upper';
let locale = fallback;
const getIntl = (language: string) => {
try {
return new Intl.Locale(language);
} catch (error) {
return new Intl.Locale(fallback);
}
};
$: intl = getIntl(locale);
const m = getMessages();
const properties: (keyof Intl.LocaleOptions)[] = [
'baseName',
'calendar',
'region',
'script',
'caseFirst',
'collation',
'hourCycle',
'language',
'numberingSystem',
'numeric'
];
</script>

<PageLayout showLocalePicker={false}>
<Input id="locale" label={m.locale()} slot="input" bind:value={locale} fullWidth />
<Grid slot="output">
{#if intl}
{#each properties as property}
<OptionSection
header={property}
support={browserCompatData?.propertiesSupport?.[property]}
hideFullSupport
>
<CodeBlock>
<HighlightValue value={intl[property] ?? m.noValue()} />
</CodeBlock>
</OptionSection>
{/each}
{/if}
</Grid>
</PageLayout>
7 changes: 5 additions & 2 deletions src/lib/components/pages/PageLayout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import LocalePicker from '$lib/components/ui/LocalePicker.svelte';
import { getMessages } from '$lib/i18n/util';
const m = getMessages();
export let showLocalePicker: boolean = true;
const m = getMessages();
</script>

<Card>
Expand All @@ -14,7 +15,9 @@
<hr />
<Spacing />
<Grid>
<LocalePicker />
{#if showLocalePicker}
<LocalePicker />
{/if}
{#if $$slots.input}
<slot name="input" />
{/if}
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/ui/HighlightValue.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script lang="ts">
import Token from "$lib/components/ui/Highlight/Token.svelte";
type Value = number | boolean | string;
export let value: number | boolean | string;
type Value = number | boolean | string | undefined;
export let value: number | boolean | string | undefined;
export let noWrap: boolean = false;
const valueType = typeof value as "string";
const formattedValue = (value: Value) =>
Expand Down
4 changes: 4 additions & 0 deletions src/lib/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,9 @@ export const routes: Route[] = [
path: 'DurationFormat',
name: 'DurationFormat',
experimental: true,
},
{
path: 'Locale',
name: 'Locale',
}
];
1 change: 1 addition & 0 deletions src/lib/types/BrowserSupport.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export type BrowserSupportDataForMethod = {
coverage?: BrowserCoverage;
optionsSupport?: BrowserSupportDataForOptions;
formattersSupport?: BrowserSupportDataForOptions;
propertiesSupport?: BrowserSupportDataForOptions;
};
102 changes: 67 additions & 35 deletions src/lib/utils/write-compat-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import bcd, {
type Browsers,
type BrowserType,
type CompatData,
type CompatStatement,
type Identifier,
type SimpleSupportStatement,
type SupportStatement
Expand All @@ -31,6 +32,16 @@ const secondaryFormatterNames = [
'selectRange'
];

const compatKey = "__compat";
const toStringKey = "toString";

const excludedPropertiesOnMethod = [compatKey, toStringKey];

type MethodsToWriteFor = FormatMethodsKeys | "Locale";
const methodsToWriteFor: MethodsToWriteFor[] = [...formatMethods, "Locale"];

const shouldAddPropertiesSupport = (method: MethodsToWriteFor) => method === "Locale";

const getPropertyFromSupportStatement = <Key extends keyof SimpleSupportStatement>(
statement: SupportStatement,
key: Key
Expand All @@ -45,7 +56,13 @@ const getSupportDataForProperty = (value: Identifier) => {
return Object.entries(value.__compat?.support ?? {}) as [BrowserName, SupportStatement][];
};

const getOptionsForProperty = (compatData: CompatData, property: FormatMethodsKeys) => {
const getPropertiesForMethod = (compatData: CompatData, property: MethodsToWriteFor) => {
const allPropertiesOnMethod = compatData.javascript.builtins.Intl[property];
return Object.entries(allPropertiesOnMethod)
.filter(([key]) => key !== property && !excludedPropertiesOnMethod.includes(key))
}

const getOptionsForProperty = (compatData: CompatData, property: MethodsToWriteFor) => {
const allPropertiesOnMethod = compatData.javascript.builtins.Intl[property][property];
const options = Object.entries(allPropertiesOnMethod).filter(([key]) => key.includes('options'));
const hasNestedObjectProperty = options && options[0] && options[0][0] === 'options_parameter';
Expand All @@ -55,7 +72,7 @@ const getOptionsForProperty = (compatData: CompatData, property: FormatMethodsKe
return options;
};

const getFormattersForProperty = (compatData: CompatData, property: FormatMethodsKeys) => {
const getFormattersForProperty = (compatData: CompatData, property: MethodsToWriteFor) => {
const allPropertiesOnMethod = compatData.javascript.builtins.Intl[property];
return Object.entries(allPropertiesOnMethod).filter(([key]) =>
secondaryFormatterNames.includes(key)
Expand Down Expand Up @@ -99,70 +116,85 @@ export const getCoverage = (data: [BrowserName, BrowserReleaseData][]): BrowserC
return "partial"
}

const optionKeyFormatter = (key: string) => {
const [, option] = key.split("_");
return option;
}

const formatSupportData = (
browsers: Browsers,
keyFormatter?: (key: string) => string
) => ([key, value]: [string, Identifier | CompatStatement]) => {
const supportDataForOption = getSupportDataForProperty(value as unknown as Identifier);
const formattedOptions = supportDataForOption
.filter(filterExludedBrowsers)
.map(browserToSupportData(browsers))
.sort(sortCompatData);
return [
keyFormatter ? keyFormatter(key) : key,
{
coverage: getCoverage(formattedOptions),
support: Object.fromEntries(formattedOptions)
}
];
}

const getCompatDataWithBrowserData = (
compatData: CompatData,
property: FormatMethodsKeys
property: MethodsToWriteFor
): BrowserSupportDataForMethod => {
const { browsers } = compatData;
const propertyData = compatData.javascript.builtins.Intl[property];
const support = getSupportDataForProperty(propertyData)
.filter(filterExludedBrowsers)
.map(browserToSupportData(browsers))
.sort(sortCompatData);
const options = getOptionsForProperty(compatData, property).map(([key, value]) => {
const supportDataForOption = getSupportDataForProperty(value as Identifier);
const formattedOptions = supportDataForOption
.filter(filterExludedBrowsers)
.map(browserToSupportData(browsers))
.sort(sortCompatData);
const [, option] = key.split('_');
return [
option,
{
coverage: getCoverage(formattedOptions),
support: Object.fromEntries(formattedOptions)
}
];
});
const formatters = getFormattersForProperty(compatData, property).map(([key, value]) => {
const supportDataForFormatter = getSupportDataForProperty(value as Identifier);
const formattedOptions = supportDataForFormatter
.filter(filterExludedBrowsers)
.map(browserToSupportData(browsers))
.sort(sortCompatData);
return [
key,
{
coverage: getCoverage(formattedOptions),
support: Object.fromEntries(formattedOptions)
}
];
});
const options = getOptionsForProperty(compatData, property).map(
formatSupportData(browsers, optionKeyFormatter)
);
const formatters = getFormattersForProperty(compatData, property)
.map(formatSupportData(browsers));
const properties = getPropertiesForMethod(compatData, property)
.map(formatSupportData(browsers));
return {
mdnUrl: propertyData?.__compat?.mdn_url,
specUrl: propertyData?.__compat?.spec_url,
support: Object.fromEntries(support) as Record<string, BrowserReleaseData>,
coverage: getCoverage(support),
optionsSupport: Object.fromEntries(options),
formattersSupport: Object.fromEntries(formatters)
formattersSupport: Object.fromEntries(formatters),
propertiesSupport: shouldAddPropertiesSupport(property)
? Object.fromEntries(properties)
: undefined,
};
};

export const writeCompatData = () => {
const writeData = formatMethods.map((method) => [
const writeData = methodsToWriteFor.map((method) => [
method,
getCompatDataWithBrowserData(bcd, method)
]);
writeFile(
resolve(process.cwd(), 'static', `Playground-compat-data.json`),
JSON.stringify(Object.fromEntries(writeData)),
JSON.stringify(Object.fromEntries(writeData.filter(([key]) => key !== "Locale"))),
(error) => {
if (error) {
console.log(error);
}
}
);
writeData.forEach(([method, data]) => {
if(method === "NumberFormat") {
writeFile(
resolve(process.cwd(), 'static', 'NumberFormat', 'NumberFormat-compat-data.json'),
JSON.stringify(data),
(error) => {
if (error) {
console.log(error);
}
}
);
}
writeFile(
resolve(process.cwd(), 'static', `${method}-compat-data.json`),
JSON.stringify(data),
Expand Down
7 changes: 7 additions & 0 deletions src/routes/Locale/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { BrowserSupportDataForMethod } from '$lib/types/BrowserSupport.types';
import type { ServerLoadEvent } from '@sveltejs/kit';
import { loadJson } from '$lib/utils/load-json';

export async function load(loadEvent: ServerLoadEvent): Promise<BrowserSupportDataForMethod> {
return loadJson(loadEvent);
}
21 changes: 21 additions & 0 deletions src/routes/Locale/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script lang="ts">
import Locale from "$lib/components/pages/Locale.svelte";
import BrowserSupport from "$lib/components/ui/BrowserSupport/BrowserSupport.svelte";
import Spacing from "$lib/components/ui/Spacing.svelte";
import { settings } from "$lib/store/settings";
import type { PageData } from './$types';
export let data: PageData;
let browserCompatData = $settings.showBrowserSupport ? data : null;
</script>

{#if $settings.showBrowserSupport}
<BrowserSupport {data} />
<Spacing />
{/if}

<Locale {browserCompatData} />

1 change: 1 addition & 0 deletions static/Locale-compat-data.json

Large diffs are not rendered by default.

0 comments on commit ad6ad05

Please sign in to comment.