Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 32 additions & 24 deletions src/main/api/studio-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2741,30 +2741,6 @@ paths:
'500':
$ref: '#/components/responses/api1InternalServerError'

/api/1/services/api/1/server/get-available-languages.json:
get:
tags:
- server
summary: Get available languages.
description: "Required role: N/A"
operationId: getAvailableLanguages
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/AvailableLanguage'
example:
- id: en
label: English
- id: es
label: Español
- id: kr
label: 한국어

/api/2/search/search:
post:
tags:
Expand Down Expand Up @@ -8213,6 +8189,38 @@ paths:
'500':
$ref: '#/components/responses/InternalServerError'

/api/2/system/available_languages:
get:
security: []
tags:
- system
summary: Get available languages in the system.
description: No permission required
operationId: getAvailableLanguages
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
response:
$ref: '#/components/schemas/ApiResponse'
languages:
type: array
items:
$ref: '#/components/schemas/AvailableLanguage'
example:
- id: en
label: English
- id: es
label: Español
- id: kr
label: 한국어
'500':
Comment thread
coderabbitai[bot] marked this conversation as resolved.
$ref: '#/components/responses/InternalServerError'

components:
schemas:
ApiResponse:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved.
* Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
Expand All @@ -25,11 +25,13 @@
import org.craftercms.studio.api.v2.dal.security.NormalizedRole;
import org.craftercms.studio.api.v2.exception.configuration.ConfigurationException;
import org.craftercms.studio.model.config.TranslationConfiguration;
import org.craftercms.studio.model.i18n.Language;
import org.craftercms.studio.model.rest.ConfigurationHistory;
import org.dom4j.Document;
import org.springframework.core.io.Resource;

import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -261,4 +263,11 @@ default String getCacheKey(String siteId, String module, String path, String env
* @throws ServiceLayerException if an error occurs while reading the groups
*/
List<NormalizedGroup> getSiteGroups(String siteId) throws ServiceLayerException;

/**
* Get the available languages in the system.
*
* @return the list of available languages
*/
Collection<Language> getAvailableLanguages() throws ServiceLayerException;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved.
* Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
Expand Down Expand Up @@ -358,6 +358,9 @@ public interface StudioConfiguration {
String BLOB_STORES_CONFIG_PATH = "studio.blob.config.path";
String BLOB_STORES_SERVERLESS_DEFAULT_CONFIG_PATH = "studio.blob.default.config.path";

// System
String CONFIGURATION_AVAILABLE_LANGUAGES = "studio.configuration.availableLanguages";

void loadConfig();

String getProperty(String key);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2024 Crafter Software Corporation. All Rights Reserved.
* Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
Expand Down Expand Up @@ -156,6 +156,7 @@ public final class RequestMappingConstants {
* System Controller
*/
public static final String SYSTEM = "/system";
public static final String AVAILABLE_LANGUAGES = "/available_languages";

/**
* Site Controller
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public final class ResultConstants {
* System Controller
*/
public static final String RESULT_KEY_PROPERTIES = "properties";
public static final String RESULT_KEY_LANGUAGES = "languages";

/**
* Exception Handler
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved.
* Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
Expand All @@ -21,8 +21,12 @@
import jakarta.validation.constraints.Size;
import org.craftercms.commons.validation.annotations.param.ValidateNoTagsParam;
import org.craftercms.commons.validation.annotations.param.ValidateStringParam;
import org.craftercms.studio.api.v1.exception.ServiceLayerException;
import org.craftercms.studio.api.v2.service.config.ConfigurationService;
import org.craftercms.studio.api.v2.service.system.SystemPropertiesService;
import org.craftercms.studio.model.i18n.Language;
import org.craftercms.studio.model.rest.Result;
import org.craftercms.studio.model.rest.ResultList;
import org.craftercms.studio.model.rest.ResultOne;
import org.craftercms.studio.model.rest.system.UpdateSystemPropertiesRequest;
import org.springframework.validation.annotation.Validated;
Expand All @@ -34,6 +38,7 @@

import static org.craftercms.studio.api.v2.service.system.SystemPropertiesService.PROPERTY_NAME_ALLOWED_PATTERN;
import static org.craftercms.studio.controller.rest.v2.RequestMappingConstants.*;
import static org.craftercms.studio.controller.rest.v2.ResultConstants.RESULT_KEY_LANGUAGES;
import static org.craftercms.studio.model.rest.ApiResponse.OK;

/**
Expand All @@ -45,10 +50,13 @@
public class SystemController {

private final SystemPropertiesService systemPropertiesService;
private final ConfigurationService configurationService;

@ConstructorProperties({"systemPropertiesService"})
public SystemController(final SystemPropertiesService systemPropertiesService) {
@ConstructorProperties({"systemPropertiesService", "configurationService"})
public SystemController(final SystemPropertiesService systemPropertiesService,
final ConfigurationService configurationService) {
this.systemPropertiesService = systemPropertiesService;
this.configurationService = configurationService;
}

@GetMapping(PROPERTIES)
Expand All @@ -67,4 +75,12 @@ public Result setSystemProperties(@Valid @RequestBody UpdateSystemPropertiesRequ
result.setResponse(OK);
return result;
}

@GetMapping(AVAILABLE_LANGUAGES)
public ResultList<Language> getAvailableLanguages() throws ServiceLayerException {
var result = new ResultList<Language>();
result.setEntities(RESULT_KEY_LANGUAGES, configurationService.getAvailableLanguages());
result.setResponse(OK);
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved.
* Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
Expand Down Expand Up @@ -33,11 +33,13 @@
import org.craftercms.studio.api.v2.exception.configuration.ConfigurationException;
import org.craftercms.studio.api.v2.service.config.ConfigurationService;
import org.craftercms.studio.model.config.TranslationConfiguration;
import org.craftercms.studio.model.i18n.Language;
import org.craftercms.studio.model.rest.ConfigurationHistory;
import org.dom4j.Document;
import org.springframework.core.io.Resource;

import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -198,4 +200,9 @@ public List<NormalizedGroup> getSiteGroups(String siteId) throws ServiceLayerExc
public Map<String, Object> legacyGetConfiguration(String site, String path) throws ServiceLayerException {
return configurationServiceInternal.legacyGetConfiguration(site, path);
}

@Override
public Collection<Language> getAvailableLanguages() throws ServiceLayerException {
return configurationServiceInternal.getAvailableLanguages();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.google.common.cache.Cache;
import org.apache.commons.configuration2.HierarchicalConfiguration;
import org.apache.commons.configuration2.tree.ImmutableNode;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;
Expand Down Expand Up @@ -52,6 +53,7 @@
import org.craftercms.studio.impl.v2.utils.XsltUtils;
import org.craftercms.studio.impl.v2.utils.security.SecurityUtils;
import org.craftercms.studio.model.config.TranslationConfiguration;
import org.craftercms.studio.model.i18n.Language;
import org.craftercms.studio.model.rest.ConfigurationHistory;
import org.dom4j.*;
import org.jspecify.annotations.NonNull;
Expand All @@ -70,14 +72,13 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ExecutionException;

import static java.lang.String.format;
import static java.lang.String.join;
import static java.util.Collections.emptyMap;
import static java.util.Collections.unmodifiableCollection;
import static org.apache.commons.io.FilenameUtils.getExtension;
import static org.apache.commons.io.FilenameUtils.normalize;
import static org.apache.commons.lang3.StringUtils.*;
Expand All @@ -101,6 +102,9 @@ public class ConfigurationServiceInternalImpl implements ConfigurationService, A
public static final String PLACEHOLDER_NAME = "name";
public static final String PLACEHOLDER_ID = "id";

private static final String CONFIG_KEY_ID = "id";
private static final String CONFIG_KEY_LABEL = "label";

/* Translation Config */
public static final String CONFIG_KEY_TRANSLATION_DEFAULT_LOCALE = "defaultLocaleCode";
public static final String CONFIG_KEY_TRANSLATION_LOCALES = "localeCodes.localeCode";
Expand Down Expand Up @@ -724,6 +728,31 @@ protected void invalidateCache(String key) {
cacheInvalidators.forEach(invalidator -> invalidator.invalidate(configurationCache, key));
}

@Override
public Collection<Language> getAvailableLanguages() throws ServiceLayerException {
try {
return (Collection<Language>) configurationCache.get(CONFIGURATION_AVAILABLE_LANGUAGES, this::loadAvailableLanguages);
} catch (ExecutionException e) {
throw new ServiceLayerException("Failed to load available languages configuration", e);
}
}

/**
* Loads the available languages from the configuration and returns them as a collection of {@link Language} objects.
*/
protected Collection<Language> loadAvailableLanguages() {
List<HierarchicalConfiguration<ImmutableNode>> languageNodes =
studioConfiguration.getSubConfigs(CONFIGURATION_AVAILABLE_LANGUAGES);

List<Language> languages = new ArrayList<>();
for (HierarchicalConfiguration<ImmutableNode> languageNode : languageNodes) {
String id = languageNode.getString(CONFIG_KEY_ID);
String label = languageNode.getString(CONFIG_KEY_LABEL);
languages.add(new Language(id, label));
}
return unmodifiableCollection(languages);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Moved from SiteServiceImpl to be able to properly cache the object
// TODO: JM: Remove unused method?
@Override
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/org/craftercms/studio/model/i18n/Language.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.craftercms.studio.model.i18n;

/**
* Represents an available language in the system. This is used for content localization and internationalization purposes.
*/
public record Language(String id, String label) {
}
17 changes: 15 additions & 2 deletions src/main/resources/crafter/studio/studio-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,9 @@ studio.security.activity.cache.config: initialCapacity=25,maximumSize=100
# Public URLs, comma separated list of regular expressions.
# The regex should not include extension and should match the query string too.
studio.security.publicUrls: >
/api/1/services/api/1/server/get-available-languages.*,/api/1/services/api/1/server/get-ui-resource-override.*,
/api/2/system/available_languages.*,
/api/2/monitoring/.+,/api/2/users/forgot_password.*,/api/2/users/set_password.*,/static-assets/.+,
/api/2/users/validate_token.*,/api/1/services/api/1/security/login.*,/api/2/users/forgot_password.*,
/api/2/users/validate_token.*,/api/2/users/forgot_password.*,
/api/2/plugin/script/reload.*
# Salt for encrypting
studio.security.cipher.salt: DgGN9xhq3GOn6zxg
Expand Down Expand Up @@ -1113,3 +1113,16 @@ studio.configuration.dashboard.contentExpiredQuery.sortBy: expired_dt
studio.api.stripSuffixes.suffixes: .json,.xml
# Urls to include for suffix stripping
studio.api.stripSuffixes.includedUrls: /api/**,/refresh.json,/authType.json

###################################################
## System Configuration ##
###################################################
studio.configuration.availableLanguages:
- id: en
label: English
- id: es
label: Español
- id: ko
label: 한국어
- id: de
label: Deutsch