Skip to content

Commit 3af8d82

Browse files
committed
chore: migrate strapi-plugin-language to Strapi 5
1 parent 44cba9b commit 3af8d82

31 files changed

+2114
-98
lines changed

.changeset/bumpy-rats-prove.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@frameless/strapi-plugin-language": major
3+
---
4+
5+
Migrate strapi-plugin-language to Strapi 5

apps/dashboard/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"dependencies": {
2323
"@_sh/strapi-plugin-ckeditor": "6.0.3",
2424
"@frameless/preview-button": "workspace:*",
25+
"@frameless/strapi-plugin-language": "workspace:*",
2526
"@strapi/design-system": "2.1.2",
2627
"@strapi/plugin-graphql": "5.33.4",
2728
"@strapi/plugin-users-permissions": "5.33.4",

apps/dashboard/src/components/components/utrecht-link.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@
3333
"bijzonderheden",
3434
"contact"
3535
]
36+
},
37+
"language": {
38+
"type": "customField",
39+
"customField": "plugin::language.language",
40+
"options": {
41+
"defaultLanguage": "nl"
42+
}
3643
}
3744
}
3845
}

apps/frontend/next-env.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3-
import "./.next/types/routes.d.ts";
3+
import "./.next/dev/types/routes.d.ts";
44

55
// NOTE: This file should not be edited
66
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# @frameless/strapi-plugin-language 1.0.0 (2024-06-10)
2+
3+
## 0.0.0
4+
5+
### Minor Changes
6+
7+
- 82fa577: Wanneer een linktekst in een andere taal is geschreven, dan kun je nu in Strapi de taal instellen. Als je dit doet verbeter je de toegankelijkheid, want dan kan de tekst met de juiste taal voorgelezen worden.
8+
9+
### Features
10+
11+
- **strapi-plugin-language:** create strapi language plugin ([a6653d3](https://github.com/frameless/strapi/commit/a6653d37ede5d8300b7a10d6f70ceb12fdfa0703))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Strapi plugin language
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import i18nLanguages from '@cospired/i18n-iso-languages';
2+
import { Combobox, ComboboxOption, Field } from '@strapi/design-system';
3+
import enJson from '@cospired/i18n-iso-languages/langs/en.json';
4+
import nlJson from '@cospired/i18n-iso-languages/langs/nl.json';
5+
6+
import { getLanguageOptions, languageCode } from '../../utils/getLanguageOptions';
7+
import { useContentLocale } from '../../hooks/useContentLocale';
8+
9+
i18nLanguages.registerLocale(enJson);
10+
i18nLanguages.registerLocale(nlJson);
11+
12+
export interface LanguageFieldFieldInputProps {
13+
attribute: {
14+
type: string;
15+
customField?: string;
16+
options?: {
17+
defaultLanguage?: string;
18+
};
19+
[key: string]: unknown;
20+
};
21+
disabled: boolean;
22+
error?: string;
23+
rawError?: unknown;
24+
hint?: string;
25+
label: string;
26+
placeholder?: string;
27+
name: string;
28+
required: boolean;
29+
unique: boolean;
30+
type: string;
31+
value: string | null;
32+
initialValue?: string;
33+
mainField?: string;
34+
35+
onChange: (event: unknown) => void;
36+
onBlur: () => void;
37+
onFocus: () => void;
38+
}
39+
40+
export const LanguageField = ({
41+
value,
42+
onChange,
43+
name,
44+
required,
45+
attribute,
46+
type,
47+
placeholder,
48+
disabled,
49+
error,
50+
label,
51+
hint,
52+
}: LanguageFieldFieldInputProps) => {
53+
const locale = useContentLocale();
54+
const languageOptions = getLanguageOptions(languageCode, locale ?? 'nl');
55+
const defaultLanguage = attribute.options?.defaultLanguage;
56+
57+
return (
58+
<Field.Root name={name} id={name} error={error} hint={hint}>
59+
<Field.Label>{label}</Field.Label>
60+
<Combobox
61+
placeholder={placeholder}
62+
aria-label={label}
63+
aria-disabled={disabled}
64+
disabled={disabled}
65+
required={required}
66+
value={value || defaultLanguage}
67+
onChange={(code: string) => onChange({ target: { name, value: code, type } })}
68+
>
69+
{languageOptions.map(({ code, name }) => (
70+
<ComboboxOption value={code} key={code}>
71+
{name}
72+
</ComboboxOption>
73+
))}
74+
</Combobox>
75+
<Field.Hint />
76+
<Field.Error />
77+
</Field.Root>
78+
);
79+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Flex } from '@strapi/design-system';
2+
import { Earth } from '@strapi/icons';
3+
4+
export const LanguageFieldIcon = () => {
5+
return (
6+
<Flex justifyContent="center" alignItems="center" width={7} height={6} hasRadius aria-hidden>
7+
<Earth fill="primary600" />
8+
</Flex>
9+
);
10+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { useEffect, useState } from 'react';
2+
3+
import { getCurrentContentLocale } from '../utils/getCurrentContentLocale';
4+
5+
export const useContentLocale = () => {
6+
const [locale, setLocale] = useState<string | null>(null);
7+
8+
useEffect(() => {
9+
const update = () => {
10+
setLocale(getCurrentContentLocale());
11+
};
12+
13+
update(); // initialize on mount
14+
window.addEventListener('popstate', update);
15+
16+
return () => window.removeEventListener('popstate', update);
17+
}, []);
18+
19+
return locale;
20+
};
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { getTranslation } from './utils/getTranslation';
2+
import { LanguageFieldIcon } from './components/LanguageFieldIcon';
3+
import { PLUGIN_ID } from './pluginId';
4+
import { getLanguageOptions, languageCode } from './utils/getLanguageOptions';
5+
import { getCurrentContentLocale } from './utils/getCurrentContentLocale';
6+
7+
type TranslateOptions = Record<string, string>;
8+
9+
const prefixPluginTranslations = (translate: TranslateOptions, pluginId: string): TranslateOptions => {
10+
if (!pluginId) {
11+
throw new TypeError("pluginId can't be empty");
12+
}
13+
return Object.keys(translate).reduce((acc, current) => {
14+
acc[`${pluginId}.${current}`] = translate[current];
15+
return acc;
16+
}, {} as TranslateOptions);
17+
};
18+
19+
export default {
20+
register(app: any) {
21+
const locale = getCurrentContentLocale() || 'nl';
22+
const optionsForStrapi = getLanguageOptions(languageCode, locale).map((lang) => ({
23+
key: lang.code,
24+
value: lang.code,
25+
metadatas: {
26+
intlLabel: {
27+
id: `${PLUGIN_ID}.${lang.code}`,
28+
defaultMessage: lang.name,
29+
},
30+
},
31+
}));
32+
app.customFields.register({
33+
name: PLUGIN_ID,
34+
pluginId: PLUGIN_ID,
35+
type: 'string',
36+
icon: LanguageFieldIcon,
37+
intlLabel: {
38+
id: getTranslation(`${PLUGIN_ID}.label`),
39+
defaultMessage: 'Select language',
40+
},
41+
intlDescription: {
42+
id: getTranslation(`${PLUGIN_ID}.description`),
43+
defaultMessage: 'Select language',
44+
},
45+
components: {
46+
Input: async () =>
47+
import('./components/LanguageField').then((module) => ({
48+
default: module.LanguageField,
49+
})),
50+
},
51+
options: {
52+
advanced: [
53+
{
54+
sectionTitle: {
55+
id: 'global.settings',
56+
defaultMessage: 'Settings',
57+
},
58+
items: [
59+
{
60+
name: 'required',
61+
type: 'checkbox',
62+
intlLabel: {
63+
id: 'form.attribute.item.requiredField',
64+
defaultMessage: 'Required field',
65+
},
66+
description: {
67+
id: 'form.attribute.item.requiredField.description',
68+
defaultMessage: "You won't be able to create an entry if this field is empty",
69+
},
70+
},
71+
72+
{
73+
intlLabel: {
74+
id: 'my-plugin.settings.defaultLanguage',
75+
defaultMessage: 'Default language',
76+
},
77+
name: 'options.defaultLanguage',
78+
type: 'select',
79+
options: optionsForStrapi,
80+
},
81+
],
82+
},
83+
],
84+
},
85+
});
86+
},
87+
async registerTranslation({ locales }: { locales: string[] }) {
88+
const importedTranslations = await Promise.all(
89+
locales.map((locale: any) => {
90+
return import(`./translations/${locale}.json`)
91+
.then(({ default: data }) => {
92+
return {
93+
data: prefixPluginTranslations(data, PLUGIN_ID),
94+
locale,
95+
};
96+
})
97+
.catch(() => {
98+
return {
99+
data: {},
100+
locale,
101+
};
102+
});
103+
}),
104+
);
105+
106+
return Promise.resolve(importedTranslations);
107+
},
108+
};

0 commit comments

Comments
 (0)