Skip to content

Commit

Permalink
feat: alternate language link component
Browse files Browse the repository at this point in the history
  • Loading branch information
Robbert committed Jul 19, 2021
1 parent 312b432 commit 8e688f9
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 0 deletions.
39 changes: 39 additions & 0 deletions components/alternate-lang-link/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!--
@license EUPL-1.2
Copyright (c) 2021 Robbert Broersma
-->

# Alternate Language Link

## HTML

- Use `hreflang` to indicate the language of the page you link to:

- `<a href="/en/" hreflang="en">English</a>`
- `<a href="/fr/" hreflang="fr">Français</a>`

- Use `lang` to for the language in which you write the link text content and the link `title` attribute. This helps screen readers pronounce the text content correctly.

- `<a ... lang="en">English</a>`
- `<a ... lang="fr">Français</a>`

- Use `aria-current="page"` to annotate the link to the page the use is on currently.

- Use `rel="alternative"` to include some old-school metadata that has no particular effect, when the content of the link target is equivalent to the current page. Together with `hreflang` it provides an opportunity to select alternate language links in HTML with a CSS selector: `a[rel~="alternative" i][hreflang]`

- Use a word separator between the links to keep the links comprehensible without CSS, so do not write `<a>EN</a><a>NL</a>`.

## Content

- Although using language codes can be a compact way to display the links, the language code is not the optimal way of describing a language. Provide the full language name, either in the link text or in the `title` attribute.

- For users that do not understand the language of the current page, it is essential to describe the language in their own language, not in the language they don't understand. For example:

- `<a href="/nl/ lang="zh">荷蘭語</a>` versus:
- `<a href="/nl/ lang="nl">Nederlands</a>`

- Country flags are not an effective way to illustrate a language, do not use a flag icon. Languages can have an official status spoken in multiple countries, so picking one flag can be discriminating. Countries can have multiple official languages, so the flag icons can be ambiguous and don't always provide the intended clarity.

## Related reading

- [Indicating the language of a link destination - by Richard Ishida, W3C](https://www.w3.org/International/questions/qa-link-lang)
12 changes: 12 additions & 0 deletions components/alternate-lang-link/bem.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @license EUPL-1.2
* Copyright (c) 2021 Robbert Broersma
*/

/* stylelint-disable-next-line block-no-empty */
.utrecht-link--alternate-lang {
}

/* stylelint-disable-next-line block-no-empty */
.utrecht-link--current-lang {
}
89 changes: 89 additions & 0 deletions components/alternate-lang-link/bem.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<!--
@license EUPL-1.2
Copyright (c) 2021 Robbert Broersma
-->

import { Meta, Story, Canvas, ArgsTable, Description } from "@storybook/addon-docs/blocks";
import clsx from "clsx";

import "../link/bem.scss";

import README from "./README.md";

export const AlternateLangLink = ({ textContent, title, current, lang, hreflang }) =>
`<a href="https://example.com/${lang}/" class="${clsx("utrecht-link", "utrecht-link--alternate-lang", {
"utrecht-link--current-lang": current,
})}"${current ? 'aria-current="page"' : ""} title="${title}" hreflang="${hreflang}" lang="${lang}"${
!current ? 'rel="alternate"' : ""
}>${textContent}</a>`;

<Meta
title="Components/Alternate Language Link"
argTypes={{
current: {
description: "This language is the current page",
control: "boolean",
},
hreflang: {
description: "Language of alternate page",
control: "text",
},
lang: {
description: "Language code for the content of the alternate page",
control: "text",
},
textContent: {
description: "Link text",
control: "text",
},
title: {
description: "Language the description for the alternate page",
control: "text",
},
}}
parameters={{
docs: {
transformSource: (_src, { args }) => AlternateLangLink(args),
},
status: "WORK IN PROGRESS",
}}
/>

<Description>{README}</Description>

Styling via the `.utrecht-link` class name with `.utrecht-link--alternate-lang` modifier class name:

<Canvas>
<Story
name="Alternate Language Link"
args={{
hreflang: "en",
lang: "en",
textContent: "EN",
title: "This page in English",
}}
>
{AlternateLangLink.bind({})}
</Story>
</Canvas>

<ArgsTable story="Alternate Language Link" />

## Current language

Styling via the `.utrecht-link` class name with `.utrecht-link--current-lang` modifier class name:

<Canvas>
<Story
name="Current Language Link"
args={{
current: true,
hreflang: "en",
lang: "en",
textContent: "EN",
title: "This page in English",
}}
>
{AlternateLangLink.bind({})}
</Story>
</Canvas>
13 changes: 13 additions & 0 deletions components/alternate-lang-link/html.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @license EUPL-1.2
* Copyright (c) 2021 Robbert Broersma
*/

@import "./bem";

.utrecht-html a[hreflang][rel~="alternate" i] {
@extend .utrecht-link--alternate-lang;
}
.utrecht-html a[hreflang][aria-current="page"] {
@extend .utrecht-link--current-lang;
}
83 changes: 83 additions & 0 deletions components/alternate-lang-link/html.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!--
@license EUPL-1.2
Copyright (c) 2021 Robbert Broersma
-->

import { Meta, Story, Canvas, ArgsTable, Description } from "@storybook/addon-docs/blocks";

import "./html.scss";

import README from "./README.md";

export const AlternateLangLink = ({ textContent, title, current, lang, hreflang }) =>
`<a href="https://example.com/${lang}/"${
current ? 'aria-current="page"' : ""
} title="${title}" hreflang="${hreflang}" lang="${lang}"${!current ? 'rel="alternate"' : ""}>${textContent}</a>`;

<Meta
title="Semantic HTML/Alternate Language Link"
argTypes={{
current: {
description: "This language is the current page",
control: "boolean",
},
hreflang: {
description: "Language of alternate page",
control: "text",
},
lang: {
description: "Language code for the content of the alternate page",
control: "text",
},
textContent: {
description: "Link text",
control: "text",
},
title: {
description: "Language the description for the alternate page",
control: "text",
},
}}
parameters={{
docs: {
transformSource: (_src, { args }) => AlternateLangLink(args),
},
status: "WORK IN PROGRESS",
}}
decorators={[(story) => `<div class="utrecht-html">${story()}</div>`]}
/>

<Description>{README}</Description>

<Canvas>
<Story
name="Alternate Language Link"
args={{
hreflang: "en",
lang: "en",
textContent: "EN",
title: "This page in English",
}}
>
{AlternateLangLink.bind({})}
</Story>
</Canvas>

<ArgsTable story="Alternate Language Link" />

## Current language

<Canvas>
<Story
name="Current Language Link"
args={{
current: true,
hreflang: "en",
lang: "en",
textContent: "EN",
title: "This page in English",
}}
>
{AlternateLangLink.bind({})}
</Story>
</Canvas>
1 change: 1 addition & 0 deletions components/html-content/html.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

/* Collection of all semantic HTML styles in the component library */

@import "../alternate-lang-link/html";
@import "../article/html";
@import "../blockquote/html";
@import "../button/html";
Expand Down

0 comments on commit 8e688f9

Please sign in to comment.