Skip to content

Commit 59b9f04

Browse files
committed
opensignup localization
1 parent 0621e00 commit 59b9f04

File tree

7 files changed

+95
-58
lines changed

7 files changed

+95
-58
lines changed

adminforth/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

adminforth/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "adminforth",
3-
"version": "1.5.8-next.17",
3+
"version": "1.5.8-next.19",
44
"description": "OpenSource Vue3 powered forth-generation admin panel",
55
"main": "dist/index.js",
66
"module": "dist/index.js",

adminforth/plugins/i18n/custom/LanguageInUserMenu.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
text-black dark:text-darkSidebarTextHover
2525
bg-black bg-opacity-10
2626
hover:brightness-110
27-
hover:bg-lightPrimaryContrast dark:hover:bg-darkPrimaryContrasts
27+
hover:text-lightPrimary dark:hover:text-darkPrimary
28+
hover:bg-lightPrimaryContrast dark:hover:bg-darkPrimaryContrast
2829
w-full text-select-none pl-5 select-none"
2930
v-for="option in options.filter((opt) => opt.value !== selectedOption.value)"
3031
@click="doChangeLang(option.value)"

adminforth/plugins/i18n/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

adminforth/plugins/i18n/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@adminforth/i18n",
3-
"version": "1.0.18",
3+
"version": "1.0.19-next.0",
44
"main": "dist/index.js",
55
"types": "dist/index.d.ts",
66
"type": "module",

adminforth/plugins/open-signup/custom/SignupPage.vue

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ import { useRoute, useRouter } from 'vue-router';
141141
import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbite';
142142
import Button from '@/afcl/Button.vue';
143143
import Link from '@/afcl/Link.vue';
144+
import { useI18n } from 'vue-i18n';
145+
146+
const { t } = useI18n();
144147
145148
const inProgress = ref(false);
146149
@@ -158,7 +161,7 @@ const sentToEmail: Ref<string> = ref('');
158161
159162
const requestEmailConfirmation = computed(() => route.meta.requestEmailConfirmation);
160163
const verifyToken = computed(() => route.query.token);
161-
const toLoginText = computed(() => `${verifyToken.value ? 'Go' : 'Back'} to login`);
164+
const toLoginText = computed(() => verifyToken.value ? t('Go to login') : t('Back to login'));
162165
const isPasswordNeeded = computed(() => !requestEmailConfirmation.value || (requestEmailConfirmation.value && verifyToken.value));
163166
164167
const user = useUserStore();
@@ -169,22 +172,25 @@ const router = useRouter();
169172
function checkPassword() {
170173
171174
if (!password.value || !passwordConfirmation.value) {
172-
return 'Please enter both password and password confirmation';
175+
return t('Please enter both password and password confirmation');
173176
}
174177
if (password.value !== passwordConfirmation.value) {
175-
return 'Passwords do not match';
178+
return t('Passwords do not match');
176179
}
177180
178-
if (password.value.length < passwordField.value.minLength) {
179-
return `Password must be at least ${passwordField.value.minLength} characters long`;
181+
if (!passwordConstraints.value) {
182+
return null;
183+
}
184+
if (password.value.length < passwordConstraints.value.minLength) {
185+
return t(`Password must be at least {minLength} characters long`, { minLength: passwordConstraints.value.minLength });
180186
}
181187
182-
if (password.value.length > passwordField.value.maxLength) {
183-
return `Password must be at most ${passwordField.value.maxLength} characters long`;
188+
if (password.value.length > passwordConstraints.value.maxLength) {
189+
return t(`Password must be at most {maxLength} characters long`, { maxLength: passwordConstraints.value.maxLength });
184190
}
185191
186-
if (passwordField.value.validation) {
187-
const valError = applyRegexValidation(password.value, passwordField.value.validation);
192+
if (passwordConstraints.value.validation) {
193+
const valError = applyRegexValidation(password.value, passwordConstraints.value.validation);
188194
if (valError) {
189195
return valError;
190196
}
@@ -213,19 +219,31 @@ const backgroundPosition = computed(() => {
213219
return coreStore.config?.loginBackgroundPosition || '1/2';
214220
});
215221
216-
const passwordField = computed(
217-
() => route.meta.passwordField
218-
)
222+
223+
const passwordConstraints: Ref<{
224+
minLength: number;
225+
maxLength: number;
226+
validation: string;
227+
}> = ref({
228+
minLength: 8,
229+
maxLength: 100,
230+
validation: '',
231+
});
219232
220233
onMounted(async () => {
221234
await coreStore.getPublicConfig();
235+
// getPasswordConstraints
236+
passwordConstraints.value = await callAdminForthApi({
237+
path: `/plugin/${route.meta.pluginInstanceId}/password-constraints`,
238+
method: 'GET',
239+
});
222240
});
223241
224242
async function doSignup() {
225243
error.value = null;
226244
const email = emailInput.value!.value;
227245
if (!email) {
228-
error.value = 'Please enter your email';
246+
error.value = t('Please enter your email');
229247
return;
230248
}
231249
if (!requestEmailConfirmation.value && checkPassword()) {
@@ -274,7 +292,7 @@ const signupAfterEmailConfirmation = async () => {
274292
});
275293
if (resp.error) {
276294
window.adminforth.alert({
277-
message: `Error fetching data: ${resp.error}`,
295+
message: t(`Error fetching data: {error}`, { error: resp.error }),
278296
variant: 'danger',
279297
});
280298
} else if (resp.redirectTo) {

adminforth/plugins/open-signup/index.ts

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import AdminForth, { AdminForthPlugin, Filters, suggestIfTypo, AdminForthDataTypes } from "adminforth";
22
import type { IAdminForth, IHttpServer, AdminForthComponentDeclaration, AdminForthResourceColumn, AdminForthResource, BeforeLoginConfirmationFunction, HttpExtra } from "adminforth";
33
import type { PluginOptions } from './types.js';
4+
import { error } from "console";
45

56

67
export default class OpenSignupPlugin extends AdminForthPlugin {
@@ -81,11 +82,6 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
8182
meta: {
8283
customLayout: true,
8384
pluginInstanceId: this.pluginInstanceId,
84-
passwordField: {
85-
minLength: passwordField.minLength,
86-
maxLength: passwordField.maxLength,
87-
validation: passwordField.validation
88-
},
8985
requestEmailConfirmation: !!this.options.confirmEmails
9086
}
9187
}
@@ -146,27 +142,43 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
146142

147143

148144
setupEndpoints(server: IHttpServer) {
145+
146+
server.endpoint({
147+
method: 'GET',
148+
path: `/plugin/${this.pluginInstanceId}/password-constraints`,
149+
noAuth: true,
150+
handler: async ({tr}) => {
151+
return {
152+
minLength: this.passwordField.minLength,
153+
maxLength: this.passwordField.maxLength,
154+
validation: await Promise.all(
155+
this.passwordField.validation.map(async ({ regExp, message }) => ({ regExp, message: await tr(message, 'opensignup') }))
156+
),
157+
};
158+
}
159+
});
160+
149161
server.endpoint({
150162
method: 'POST',
151163
path: `/plugin/${this.pluginInstanceId}/complete-verified-signup`,
152164
noAuth: true,
153-
handler: async ({ body, response, headers, query, cookies }) => {
165+
handler: async ({ body, response, headers, query, cookies, tr }) => {
154166
const { token, password } = body;
155167
const { email } = await this.adminforth.auth.verify(token, 'tempVerifyEmailToken', false);
156168
if (!email) {
157169
return { error: 'Invalid token', ok: false };
158170
}
159171

160172
if(!password) {
161-
return { error: 'Password is required', ok: false };
173+
return { error: tr('Password is required', 'opensignup'), ok: false };
162174
}
163175
const userRecord = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
164176
if (!userRecord) {
165-
return { error: 'User not found', ok: false };
177+
return { error: tr('User not found'), ok: false };
166178
}
167179

168180
if (userRecord[this.options.confirmEmails.emailConfirmedField]) {
169-
return { error: 'Email already confirmed', ok: false };
181+
return { error: tr('Email already confirmed'), ok: false };
170182
}
171183

172184
await this.adminforth.resource(this.authResource.resourceId).update(userRecord[this.authResource.columns.find((col) => col.primaryKey).name], {
@@ -181,7 +193,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
181193
method: 'POST',
182194
path: `/plugin/${this.pluginInstanceId}/signup`,
183195
noAuth: true,
184-
handler: async ({ body, response, headers, query, cookies }) => {
196+
handler: async ({ body, response, headers, query, cookies, tr }) => {
185197
const { email, url, password } = body;
186198

187199
// validate email
@@ -196,15 +208,21 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
196208
// validate password
197209
if (!this.options.confirmEmails) {
198210
if (password.length < this.passwordField.minLength) {
199-
return { error: `Password must be at least ${this.passwordField.minLength} characters long`, ok: false };
211+
return {
212+
error: tr(`Password must be at least ${this.passwordField.minLength} characters long`, 'opensignup'),
213+
ok: false
214+
};
200215
}
201216
if (password.length > this.passwordField.maxLength) {
202-
return { error: `Password must be at most ${this.passwordField.maxLength} characters long`, ok: false };
217+
return {
218+
error: tr(`Password must be at most ${this.passwordField.maxLength} characters long`, 'opensignup'),
219+
ok: false
220+
};
203221
}
204222
if (this.passwordField.validation) {
205223
for (const { regExp, message } of this.passwordField.validation) {
206224
if (!new RegExp(regExp).test(password)) {
207-
return { error: message, ok: false };
225+
return { error: tr(message, 'opensignup'), ok: false };
208226
}
209227
}
210228
}
@@ -213,7 +231,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
213231
// first check again if email already exists
214232
const existingUser = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
215233
if ((!this.options.confirmEmails && existingUser) || (this.options.confirmEmails && existingUser?.[this.emailConfirmedField.name])) {
216-
return { error: 'Email already exists', ok: false };
234+
return { error: tr('Email already exists', 'opensignup'), ok: false };
217235
}
218236

219237
// create user
@@ -237,40 +255,40 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
237255

238256
const verifyToken = this.adminforth.auth.issueJWT({email, issuer: brandName }, 'tempVerifyEmailToken', '2h');
239257
process.env.HEAVY_DEBUG && console.log('🐛Sending reset tok to', verifyToken);
240-
const emailText = `
258+
const emailText = tr(`
241259
Dear user,
242-
Welcome to ${brandName}!
260+
Welcome to {brandName}!
243261
244262
To confirm your email, click the link below:\n\n
245263
246-
${url}?verifyToken=${verifyToken}\n\n
264+
{url}?verifyToken={verifyToken}\n\n
247265
248266
If you didn't request this, please ignore this email.\n\n
249267
Link is valid for 2 hours.\n\n
250268
251269
Thanks,
252-
The ${brandName} Team
270+
The {brandName} Team
253271
254-
`;
272+
`, 'opensignup', { brandName, url, verifyToken }
273+
);
255274

256-
const emailHtml = `
257-
<html>
258-
<head></head>
259-
<body>
260-
<p>Dear user,</p>
261-
<p>Welcome to ${brandName}!</p>
262-
<p>To confirm your email, click the link below:</p>
263-
<a href="${url}?token=${verifyToken}">Confirm email</a>
264-
<p>If you didn't request this, please ignore this email.</p>
265-
<p>Link is valid for 2 hours.</p>
266-
<p>Thanks,</p>
267-
<p>The ${brandName} Team</p>
268-
</body>
269-
</html>
270-
271-
272-
`;
273-
const emailSubject = `Signup request at ${brandName}`;
275+
const emailHtml = tr(`
276+
<html>
277+
<head></head>
278+
<body>
279+
<p>Dear user,</p>
280+
<p>Welcome to {brandName}!</p>
281+
<p>To confirm your email, click the link below:</p>
282+
<a href="{url}?token={verifyToken}">Confirm email</a>
283+
<p>If you didn't request this, please ignore this email.</p>
284+
<p>Link is valid for 2 hours.</p>
285+
<p>Thanks,</p>
286+
<p>The {brandName} Team</p>
287+
</body>
288+
</html>
289+
`, 'opensignup', { brandName, url, verifyToken });
290+
291+
const emailSubject = tr(`Signup request at {brandName}`, 'opensignup', { brandName });
274292

275293
// send email with AWS SES this.options.providerOptions.AWS_SES
276294
this.options.confirmEmails.adapter.sendEmail(this.options.confirmEmails.sendFrom, email, emailText, emailHtml, emailSubject);

0 commit comments

Comments
 (0)