/*
* This file is part of LanternServer, licensed under the MIT License (MIT).
*
* Copyright (c) LanternPowered <https://www.lanternpowered.org>
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.lanternpowered.server.text.gson;
import static org.lanternpowered.server.text.gson.TextConstants.TRANSLATABLE;
import static org.lanternpowered.server.text.gson.TextConstants.TRANSLATABLE_ARGS;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import io.netty.util.concurrent.FastThreadLocal;
import org.lanternpowered.server.text.LanternTextSerializer;
import org.lanternpowered.server.text.translation.MinecraftTranslation;
import org.lanternpowered.server.text.translation.TranslationManager;
import org.lanternpowered.server.util.FastThreadLocals;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.TextRepresentable;
import org.spongepowered.api.text.TranslatableText;
import org.spongepowered.api.text.serializer.TextSerializers;
import org.spongepowered.api.text.translation.Translation;
import java.lang.reflect.Type;
import java.util.Locale;
public final class JsonTextTranslatableSerializer extends JsonTextBaseSerializer implements JsonSerializer<TranslatableText>,
JsonDeserializer<TranslatableText> {
private final static FastThreadLocal<Locale> currentLocale = FastThreadLocals.withInitial(() -> Locale.ENGLISH);
/**
* Sets the current locale that should be used to translate all
* the text components if {@link #networkingFormat} is set to true.
*
* <p>This will only be applied to the current thread, so this will
* can be used in concurrent environments.</p>
*
* @param locale the locale
*/
public static void setCurrentLocale(Locale locale) {
currentLocale.set(locale);
}
/**
* Removes the current locale that is attached to the thread, toggling
* the locale back to the default.
*/
public static void removeCurrentLocale() {
currentLocale.remove();
}
public static Locale getCurrentLocale() {
return currentLocale.get();
}
private final TranslationManager translationManager;
private final boolean networkingFormat;
private final boolean removeComplexity;
JsonTextTranslatableSerializer(TranslationManager translationManager, boolean networkingFormat, boolean removeComplexity) {
this.translationManager = translationManager;
this.networkingFormat = networkingFormat;
this.removeComplexity = removeComplexity;
}
@Override
public TranslatableText deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject obj = element.getAsJsonObject();
final String name = obj.get(TRANSLATABLE).getAsString();
final Translation translation = this.translationManager.get(name);
final Object[] arguments;
if ((element = obj.get(TRANSLATABLE_ARGS)) != null) {
final Text[] with = context.deserialize(element, Text[].class);
arguments = new Object[with.length];
System.arraycopy(with, 0, arguments, 0, with.length);
} else {
arguments = new Object[0];
}
final TranslatableText.Builder builder = Text.builder(translation, arguments);
deserialize(obj, builder, context);
return builder.build();
}
@SuppressWarnings("deprecation")
@Override
public JsonElement serialize(TranslatableText src, Type typeOfSrc, JsonSerializationContext context) {
final Translation translation = src.getTranslation();
if (this.networkingFormat && !(translation instanceof MinecraftTranslation)) {
final ImmutableList<Object> arguments = src.getArguments();
final Object[] rawArguments = arguments.toArray(new Object[arguments.size()]);
final Locale locale = currentLocale.get();
for (int i = 0; i < rawArguments.length; i++) {
Object object = rawArguments[i];
if (object instanceof TextRepresentable) {
if (!(object instanceof Text)) {
object = ((TextRepresentable) object).toText();
}
rawArguments[i] = ((LanternTextSerializer) TextSerializers.LEGACY_FORMATTING_CODE)
.serialize((Text) object, locale);
} else {
rawArguments[i] = object.toString();
}
}
final String content = src.getTranslation().get(locale, rawArguments);
return JsonTextLiteralSerializer.serializeLiteralText(src, content, context, this.removeComplexity);
}
final JsonObject obj = new JsonObject();
obj.addProperty(TRANSLATABLE, src.getTranslation().getId());
final ImmutableList<Object> arguments = src.getArguments();
if (!arguments.isEmpty()) {
final JsonArray argumentsArray = new JsonArray();
for (Object object : arguments) {
// Only primitive strings and text json is allowed,
// so we need to convert the objects if possible
if (object instanceof TextRepresentable) {
if (!(object instanceof Text)) {
object = ((TextRepresentable) object).toText();
}
argumentsArray.add(context.serialize(object, Text.class));
} else {
argumentsArray.add(new JsonPrimitive(object.toString()));
}
}
obj.add(TRANSLATABLE_ARGS, argumentsArray);
}
serialize(obj, src, context);
return obj;
}
}