Skip to content

Commit

Permalink
feat: add internationalization (i18n)
Browse files Browse the repository at this point in the history
  • Loading branch information
Silje Christensen authored and siljec committed Aug 30, 2023
1 parent 0b0970a commit 5cb0387
Show file tree
Hide file tree
Showing 29 changed files with 1,141 additions and 44 deletions.
1 change: 1 addition & 0 deletions components/breadcrumbs/locales/en/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{\"breadcrumbs.ariaLabel\":\"You are here\"}");
20 changes: 20 additions & 0 deletions components/breadcrumbs/locales/en/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: en\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"

#. Default screenreader message for the breadcrumb component
#. js-lingui-explicit-id
#: components/breadcrumbs/w-breadcrumbs.vue:9
msgid "breadcrumbs.ariaLabel"
msgstr "You are here"
1 change: 1 addition & 0 deletions components/breadcrumbs/locales/nb/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{\"breadcrumbs.ariaLabel\":\"Her er du\"}");
20 changes: 20 additions & 0 deletions components/breadcrumbs/locales/nb/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: nb\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"

#. Default screenreader message for the breadcrumb component
#. js-lingui-explicit-id
#: components/breadcrumbs/w-breadcrumbs.vue:9
msgid "breadcrumbs.ariaLabel"
msgstr "Her er du"
10 changes: 9 additions & 1 deletion components/breadcrumbs/w-breadcrumbs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@
import { h, Fragment } from 'vue'
import { interleave } from '@warp-ds/core/breadcrumbs'
import { breadcrumbs as ccBreadcrumbs } from "@warp-ds/css/component-classes"
import { i18n } from '@lingui/core';
const props = defineProps({
ariaLabel: { type: String, default: 'Her er du' }
ariaLabel: { type: String, default: i18n._(
/*i18n*/ {
id: 'breadcrumbs.ariaLabel',
message: 'You are here',
comment: 'Default screenreader message for the breadcrumb component',
}) }
});
const isFragment = vnode => vnode.type === Fragment
Expand All @@ -37,4 +43,6 @@ const Breadcrumbify = (_, context) => {
<script>
export const wBreadcrumbSeparator = h('span', { ariaHidden: true, class: ccBreadcrumbs.separator }, '/')
export default { name: 'wBreadcrumbs' }
import { activateI18n } from '../util/i18n';
await activateI18n('breadcrumbs');
</script>
1 change: 1 addition & 0 deletions components/button/locales/en/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{\"button.aria.loading\":\"Loading...\"}");
20 changes: 20 additions & 0 deletions components/button/locales/en/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: en\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"

#. Screenreader message for buttons that are loading
#. js-lingui-explicit-id
#: components/button/w-button.vue:30
msgid "button.aria.loading"
msgstr "Loading..."
1 change: 1 addition & 0 deletions components/button/locales/nb/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{\"button.aria.loading\":\"Laster...\"}");
20 changes: 20 additions & 0 deletions components/button/locales/nb/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: nb\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"

#. Screenreader message for buttons that are loading
#. js-lingui-explicit-id
#: components/button/w-button.vue:30
msgid "button.aria.loading"
msgstr "Laster..."
15 changes: 13 additions & 2 deletions components/button/w-button.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
<template>
<component :is="href ? 'a' : 'button'" :href="href" :class="buttonClass" v-bind="saneDefaults">
<slot>{{ label }}</slot>
<span v-if="loading" role="progressbar" aria-valuenow="0" aria-valuetext="Laster..." :class="ccButton.a11y" />
<span v-if="loading" role="progressbar" aria-valuenow="0" :aria-valuetext="ariaValueText" :class="ccButton.a11y" />
</component>
</template>

<script>
export default { name: 'wButton' }
import { activateI18n } from '../util/i18n';
await activateI18n('button');
</script>

<script setup>
import { computed, useAttrs } from 'vue'
import { button as ccButton } from '@warp-ds/css/component-classes';
import { i18n } from '@lingui/core';
const buttonTypes = [
'primary',
Expand All @@ -34,7 +37,15 @@ const props = defineProps({
pill: Boolean,
loading: Boolean,
href: String,
label: String
label: String,
ariaValueText: {
type: String,
default: i18n._({
id: 'button.aria.loading',
message: 'Loading...',
comment: 'Screenreader message for buttons that are loading'
})
},
})
const buttonClass = computed(() => ({
Expand Down
1 change: 1 addition & 0 deletions components/forms/locales/en/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{\"forms.field.label.optional\":\"(optional)\",\"forms.affix.searchIconSvgTitle\":\"Magnifying glass\"}");
26 changes: 26 additions & 0 deletions components/forms/locales/en/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: en\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"

#. Shown after label when marked as optional
#. js-lingui-explicit-id
#: components/forms/w-field.vue:75
msgid "forms.field.label.optional"
msgstr "(optional)"

#. SVG title for search icon
#. js-lingui-explicit-id
#: components/forms/w-affix.vue:27
msgid "forms.affix.searchIconSvgTitle"
msgstr "Magnifying glass"
1 change: 1 addition & 0 deletions components/forms/locales/nb/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{\"forms.field.label.optional\":\"(valgfritt)\",\"forms.affix.searchIconSvgTitle\":\"Forstørrelsesglass\"}");
26 changes: 26 additions & 0 deletions components/forms/locales/nb/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: nb\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"

#. Shown after label when marked as optional
#. js-lingui-explicit-id
#: components/forms/w-field.vue:75
msgid "forms.field.label.optional"
msgstr "(valgfritt)"

#. SVG title for search icon
#. js-lingui-explicit-id
#: components/forms/w-affix.vue:27
msgid "forms.affix.searchIconSvgTitle"
msgstr "Forstørrelsesglass"
9 changes: 7 additions & 2 deletions components/forms/w-affix.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
<template>
<component :is="label ? 'div' : 'button'" :class="wrapperClass">
<svg v-if="clear" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><title>X</title><path fill="currentColor" fill-rule="evenodd" d="M4.03 2.97a.75.75 0 00-1.06 1.06L6.94 8l-3.97 3.97a.75.75 0 101.06 1.06L8 9.06l3.97 3.97a.75.75 0 101.06-1.06L9.06 8l3.97-3.97a.75.75 0 00-1.06-1.06L8 6.94 4.03 2.97z" clip-rule="evenodd"/></svg>
<svg v-else-if="search" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><title>Forstørrelsesglass</title><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" clip-path="url(#nra-cclip0)"><path d="M8.796 11.803A5.684 5.684 0 104.349 1.341a5.684 5.684 0 004.447 10.462zM11 11l4 4"/></g><defs><clipPath id="nra-cclip0"><path fill="currentColor" d="M0 0h16v16H0z"/></clipPath></defs></svg>
<svg v-else-if="search" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><title>{{ svgTitle }}</title><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" clip-path="url(#nra-cclip0)"><path d="M8.796 11.803A5.684 5.684 0 104.349 1.341a5.684 5.684 0 004.447 10.462zM11 11l4 4"/></g><defs><clipPath id="nra-cclip0"><path fill="currentColor" d="M0 0h16v16H0z"/></clipPath></defs></svg>
<span :class="labelClass" v-else-if="label">{{ label }}</span>
</component>
</template>

<script>
import { suffix, prefix } from '@warp-ds/css/component-classes'
import { computed } from 'vue'
import { activateI18n } from '../util/i18n';
import { i18n } from '@lingui/core';
await activateI18n('forms');
export default {
name: 'wAffix',
Expand All @@ -20,14 +24,15 @@ export default {
label: String
},
setup(props) {
const svgTitle = i18n._( { id: 'forms.affix.searchIconSvgTitle', message: 'Magnifying glass', comment: 'SVG title for search icon' });
const classBase = computed(() => props.prefix ? prefix : suffix)
const wrapperClass = computed(() => ({
[classBase.value.wrapper]: true,
[props.label ? classBase.value.wrapperWithLabel : classBase.value.wrapperWithIcon]: true
}))
const labelClass = computed(() => classBase.value.label)
return { wrapperClass, labelClass }
return { wrapperClass, labelClass, svgTitle }
}
}
</script>
9 changes: 7 additions & 2 deletions components/forms/w-field.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<component :is="as" :class="{[ccInput.wrapper]: true, [$attrs.class || '']: true}" :role="role" v-bind="wrapperAria">
<component :is="labelType" v-if="label" :class="{[ccLabel.label]: true, [ccLabel.labelInvalid]: hasErrorMessage}" :id="labelId" :for="labelFor" :role="valueOrUndefined(labelLevel, 'heading')" :aria-level="valueOrUndefined(labelLevel, labelLevel)">{{ label }}<span v-if="optional" :class="ccLabel.optional"> (valgfritt)</span></component>
<component :is="labelType" v-if="label" :class="{[ccLabel.label]: true, [ccLabel.labelInvalid]: hasErrorMessage}" :id="labelId" :for="labelFor" :role="valueOrUndefined(labelLevel, 'heading')" :aria-level="valueOrUndefined(labelLevel, labelLevel)">{{ label }}<span v-if="optional" :class="ccLabel.optional">{{ optionalHelperText }}</span></component>
<slot :triggerValidation="triggerValidation" :labelFor="id" :labelId="labelId" :aria="aria" :hasValidationErrors="hasValidationErrors" />
<slot name="control" :form="collector" />
<div :class="{[ccHelpText.helpText]: true, [ccHelpText.helpTextInvalid]: hasErrorMessage}" v-if="hint || hasErrorMessage">
Expand All @@ -17,6 +17,10 @@ import { input as ccInput, label as ccLabel, helpText as ccHelpText} from '@warp
import { createValidation } from './validation';
import { id } from '#util';
import { modelProps } from 'create-v-model';
import { i18n } from '@lingui/core';
import { activateI18n } from '../util/i18n';
await activateI18n('forms');
export const fieldProps = {
id,
Expand Down Expand Up @@ -68,8 +72,9 @@ export default {
'aria-required': props.required && true
}))
const wrapperAria = computed(() => valueOrUndefined(isFieldset.value, aria.value))
const optionalHelperText = i18n._({ id: 'forms.field.label.optional', message: '(optional)', comment: 'Shown after label when marked as optional'});
const hasValidationErrors = computed(() => !!hasErrorMessage.value);
return { triggerValidation, validationMsg, hasErrorMessage, labelType, labelFor, labelId, hintId, errorId, aria, wrapperAria, collector, valueOrUndefined, ccInput, ccLabel, ccHelpText, hasValidationErrors }
return { triggerValidation, validationMsg, hasErrorMessage, labelType, labelFor, labelId, hintId, errorId, aria, wrapperAria, collector, valueOrUndefined, ccInput, ccLabel, ccHelpText, hasValidationErrors, optionalHelperText }
}
}
</script>
1 change: 1 addition & 0 deletions components/modal/locales/en/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{}");
14 changes: 14 additions & 0 deletions components/modal/locales/en/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: en\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
1 change: 1 addition & 0 deletions components/modal/locales/nb/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{}");
14 changes: 14 additions & 0 deletions components/modal/locales/nb/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: nb\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
1 change: 1 addition & 0 deletions components/pill/locales/en/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{}");
14 changes: 14 additions & 0 deletions components/pill/locales/en/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: en\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
1 change: 1 addition & 0 deletions components/pill/locales/nb/messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*eslint-disable*/export const messages=JSON.parse("{}");
14 changes: 14 additions & 0 deletions components/pill/locales/nb/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-08-03 14:10+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: nb\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
29 changes: 29 additions & 0 deletions components/util/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { i18n } from '@lingui/core';

function detectLocale() {
const supportedLocales = ['en', 'nb'];
const defaultLocale = 'en';
try {
const htmlLocale = document.documentElement.lang;

return (
supportedLocales.find(
(locale) =>
htmlLocale === locale || htmlLocale.toLowerCase().includes(locale)
) || defaultLocale
);
} catch (e) {
console.warn('could not detect locale, falling back to source locale', e);
return defaultLocale;
}
}

export async function activateI18n(pkg: string, locale?: string) {
const resolvedLocale = locale ?? detectLocale();
const { messages } = await import(
`../${pkg}/locales/${resolvedLocale}/messages.mjs`
);

i18n.load(resolvedLocale, messages);
i18n.activate(resolvedLocale);
}
Loading

0 comments on commit 5cb0387

Please sign in to comment.