Skip to content

Commit

Permalink
OF-2624: Try to answer data forms in users' preferred language
Browse files Browse the repository at this point in the history
When a user is requesting a data form, try to localize the text in the form according to the user's preferred language.

In this commit, the preferred language is being obtained from the session of a locally connected user. This will not work for federated users.

As a fallback, the default langague as configured in Openfire is used (as is already the case prior to this commit).
  • Loading branch information
guusdk committed Aug 1, 2023
1 parent 5f135aa commit d0da359
Show file tree
Hide file tree
Showing 18 changed files with 465 additions and 412 deletions.
2 changes: 2 additions & 0 deletions i18n/src/main/resources/openfire_i18n.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,8 @@ index.local=Locale / Timezone:
index.process_owner=OS Process Owner:
index.memory=Java Memory
index.memory_usage_description={0} MB of {1} MB ({2}%) used
index.available_users=Available Users
index.available_users_sessions=Available Users Sessions
index.update.alert=Update information
index.update.info=Server version {0} is now available. Click {1}here{2} to download or read the \
{3}change log{4} for more information.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
* Copyright (C) 2004-2008 Jive Software, 2023 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -111,7 +111,7 @@ public void add(String username, Element data) {
Node node = pepService.getNode( data.getNamespaceURI() );
if ( node == null )
{
PubSubEngine.CreateNodeResponse response = PubSubEngine.createNodeHelper( pepService, owner, pepService.getDefaultNodeConfiguration( true ).getConfigurationForm().getElement(), data.getNamespaceURI(), PRIVATE_DATA_PUBLISHING_OPTIONS );
PubSubEngine.CreateNodeResponse response = PubSubEngine.createNodeHelper( pepService, owner, pepService.getDefaultNodeConfiguration( true ).getConfigurationForm(null).getElement(), data.getNamespaceURI(), PRIVATE_DATA_PUBLISHING_OPTIONS );
node = response.newNode;

if ( node == null )
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2008 Jive Software, 2022 Ignite Realtime Foundation. All rights reserved.
* Copyright (C) 2005-2008 Jive Software, 2022-2023 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1273,6 +1273,20 @@ public void setConflictKickLimit(int limit) {
CONFLICT_LIMIT.setValue(limit);
}

public Locale getLocaleForSession(JID address)
{
if (address == null || !XMPPServer.getInstance().isLocal(address)) {
return null;
}

final ClientSession session = getSession(address);
if (session == null) {
return null;
}

return session.getLanguage();
}

private class ClientSessionListener implements ConnectionCloseListener {
/**
* Handle a session that just closed.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2008 Jive Software. All rights reserved.
* Copyright (C) 2005-2008 Jive Software, 2023 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -50,6 +50,8 @@ protected void addStageInformation(SessionData data, Element command) {

@Override
public void execute(SessionData data, Element command) {
final Locale preferredLocale = SessionManager.getInstance().getLocaleForSession(data.getOwner());

DataForm form = new DataForm(DataForm.Type.result);

FormField field = form.addField();
Expand All @@ -59,25 +61,25 @@ public void execute(SessionData data, Element command) {

field = form.addField();
field.setType(FormField.Type.text_single);
field.setLabel(LocaleUtils.getLocalizedString("index.server_name"));
field.setLabel(LocaleUtils.getLocalizedString("index.server_name", preferredLocale));
field.setVariable("name");
field.addValue(AdminConsole.getAppName());

field = form.addField();
field.setType(FormField.Type.text_single);
field.setLabel(LocaleUtils.getLocalizedString("index.version"));
field.setLabel(LocaleUtils.getLocalizedString("index.version", preferredLocale));
field.setVariable("version");
field.addValue(AdminConsole.getVersionString());

field = form.addField();
field.setType(FormField.Type.text_single);
field.setLabel(LocaleUtils.getLocalizedString("index.domain_name"));
field.setLabel(LocaleUtils.getLocalizedString("index.domain_name", preferredLocale));
field.setVariable("domain");
field.addValue(XMPPServer.getInstance().getServerInfo().getXMPPDomain());

field = form.addField();
field.setType(FormField.Type.text_single);
field.setLabel(LocaleUtils.getLocalizedString("index.jvm"));
field.setLabel(LocaleUtils.getLocalizedString("index.jvm", preferredLocale));
field.setVariable("os");
String vmName = System.getProperty("java.vm.name");
if (vmName == null) {
Expand All @@ -90,7 +92,7 @@ public void execute(SessionData data, Element command) {

field = form.addField();
field.setType(FormField.Type.text_single);
field.setLabel(LocaleUtils.getLocalizedString("index.uptime"));
field.setLabel(LocaleUtils.getLocalizedString("index.uptime", preferredLocale));
field.setVariable("uptime");
field.addValue(XMPPDateTimeFormat.format(XMPPServer.getInstance().getServerInfo().getLastStarted()));

Expand All @@ -105,7 +107,7 @@ public void execute(SessionData data, Element command) {
double percentUsed = 100 - percentFree;
field = form.addField();
field.setType(FormField.Type.text_single);
field.setLabel(LocaleUtils.getLocalizedString("index.memory"));
field.setLabel(LocaleUtils.getLocalizedString("index.memory", preferredLocale));
field.setVariable("memory");
field.addValue(mbFormat.format(usedMemory) + " MB of " + mbFormat.format(maxMemory) + " MB (" +
percentFormat.format(percentUsed) + "%) used");
Expand All @@ -122,13 +124,13 @@ public void execute(SessionData data, Element command) {
}
field = form.addField();
field.setType(FormField.Type.text_single);
field.setLabel("Available Users");
field.setLabel(LocaleUtils.getLocalizedString("index.available_users", preferredLocale));
field.setVariable("activeusersnum");
field.addValue(users.size());

field = form.addField();
field.setType(FormField.Type.text_single);
field.setLabel("Available Users Sessions");
field.setLabel(LocaleUtils.getLocalizedString("index.available_users_sessions", preferredLocale));
field.setVariable("sessionsnum");
field.addValue(availableSessions);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
* Copyright (C) 2004-2008 Jive Software, 2023 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,18 +16,11 @@

package org.jivesoftware.openfire.muc.spi;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;

import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.openfire.muc.ConflictException;
import org.jivesoftware.openfire.muc.ForbiddenException;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MultiUserChatService;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.muc.*;
import org.jivesoftware.util.ElementUtil;
import org.jivesoftware.util.LocaleUtils;
import org.slf4j.Logger;
Expand All @@ -38,6 +31,11 @@
import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.locks.Lock;

/**
* This class is responsible for handling packets with namespace jabber:iq:register that were
* sent to the MUC service. MultiUserChatServer will receive all the IQ packets and if the
Expand All @@ -49,59 +47,6 @@ class IQMUCRegisterHandler {

private static final Logger Log = LoggerFactory.getLogger(IQMUCRegisterHandler.class);

private static final Element probeResult;

static {
// Create the registration form of the room which contains information
// such as: first name, last name and nickname.
final DataForm registrationForm = new DataForm(DataForm.Type.form);
registrationForm.setTitle(LocaleUtils.getLocalizedString("muc.form.reg.title"));
registrationForm.addInstruction(LocaleUtils
.getLocalizedString("muc.form.reg.instruction"));

final FormField fieldForm = registrationForm.addField();
fieldForm.setVariable("FORM_TYPE");
fieldForm.setType(FormField.Type.hidden);
fieldForm.addValue("http://jabber.org/protocol/muc#register");

final FormField fieldReg = registrationForm.addField();
fieldReg.setVariable("muc#register_first");
fieldReg.setType(FormField.Type.text_single);
fieldReg.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.first-name"));
fieldReg.setRequired(true);

final FormField fieldLast = registrationForm.addField();
fieldLast.setVariable("muc#register_last");
fieldLast.setType(FormField.Type.text_single);
fieldLast.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.last-name"));
fieldLast.setRequired(true);

final FormField fieldNick = registrationForm.addField();
fieldNick.setVariable("muc#register_roomnick");
fieldNick.setType(FormField.Type.text_single);
fieldNick.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.nickname"));
fieldNick.setRequired(true);

final FormField fieldUrl = registrationForm.addField();
fieldUrl.setVariable("muc#register_url");
fieldUrl.setType(FormField.Type.text_single);
fieldUrl.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.url"));

final FormField fieldMail = registrationForm.addField();
fieldMail.setVariable("muc#register_email");
fieldMail.setType(FormField.Type.text_single);
fieldMail.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.email"));

final FormField fieldFaq = registrationForm.addField();
fieldFaq.setVariable("muc#register_faqentry");
fieldFaq.setType(FormField.Type.text_single);
fieldFaq.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.faqentry"));

// Create the probeResult and add the registration form
probeResult = DocumentHelper.createElement(QName.get("query", "jabber:iq:register"));
probeResult.add(registrationForm.getElement());
}

private final MultiUserChatService mucService;

public IQMUCRegisterHandler(MultiUserChatService mucService) {
Expand All @@ -121,6 +66,8 @@ public IQ handleIQ(IQ packet) {
return reply;
}

final Locale preferredLocale = SessionManager.getInstance().getLocaleForSession(packet.getFrom());

final Lock lock = mucService.getChatRoomLock(name);
lock.lock();
try {
Expand All @@ -146,7 +93,55 @@ else if (!room.isRegistrationEnabled() ||
if (IQ.Type.get == packet.getType()) {
reply = IQ.createResultIQ(packet);
String nickname = room.getReservedNickname(packet.getFrom());
Element currentRegistration = probeResult.createCopy();

// Create the registration form of the room which contains information
// such as: first name, last name and nickname.
final DataForm registrationForm = new DataForm(DataForm.Type.form);
registrationForm.setTitle(LocaleUtils.getLocalizedString("muc.form.reg.title", preferredLocale));
registrationForm.addInstruction(LocaleUtils.getLocalizedString("muc.form.reg.instruction", preferredLocale));

final FormField fieldForm = registrationForm.addField();
fieldForm.setVariable("FORM_TYPE");
fieldForm.setType(FormField.Type.hidden);
fieldForm.addValue("http://jabber.org/protocol/muc#register");

final FormField fieldReg = registrationForm.addField();
fieldReg.setVariable("muc#register_first");
fieldReg.setType(FormField.Type.text_single);
fieldReg.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.first-name", preferredLocale));
fieldReg.setRequired(true);

final FormField fieldLast = registrationForm.addField();
fieldLast.setVariable("muc#register_last");
fieldLast.setType(FormField.Type.text_single);
fieldLast.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.last-name", preferredLocale));
fieldLast.setRequired(true);

final FormField fieldNick = registrationForm.addField();
fieldNick.setVariable("muc#register_roomnick");
fieldNick.setType(FormField.Type.text_single);
fieldNick.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.nickname", preferredLocale));
fieldNick.setRequired(true);

final FormField fieldUrl = registrationForm.addField();
fieldUrl.setVariable("muc#register_url");
fieldUrl.setType(FormField.Type.text_single);
fieldUrl.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.url", preferredLocale));

final FormField fieldMail = registrationForm.addField();
fieldMail.setVariable("muc#register_email");
fieldMail.setType(FormField.Type.text_single);
fieldMail.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.email", preferredLocale));

final FormField fieldFaq = registrationForm.addField();
fieldFaq.setVariable("muc#register_faqentry");
fieldFaq.setType(FormField.Type.text_single);
fieldFaq.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.faqentry", preferredLocale));

// Create the probeResult and add the registration form
Element currentRegistration = DocumentHelper.createElement(QName.get("query", "jabber:iq:register"));
currentRegistration.add(registrationForm.getElement());

if (nickname != null) {
// The user is already registered with the room so answer a completed form
ElementUtil.setProperty(currentRegistration, "query.registered", null);
Expand Down
Loading

0 comments on commit d0da359

Please sign in to comment.