diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs
index cd48b6de716..d2ed6e04346 100644
--- a/Content.Server/Chat/Systems/ChatSystem.cs
+++ b/Content.Server/Chat/Systems/ChatSystem.cs
@@ -241,6 +241,17 @@ public void TrySendInGameICMessage(
         if (string.IsNullOrEmpty(message))
             return;
 
+        // Check if the message is in sign language
+        if (desiredType == InGameICChatType.Speak || desiredType == InGameICChatType.Whisper)
+        {
+            var language = languageOverride ?? _language.GetLanguage(source);
+            if (language.SignLanguage ?? false)
+            {
+                SendEntityEmote(source, message, range, nameOverride, ignoreActionBlocker, signLanguage: true, languageOverride: languageOverride);
+                return;
+            }
+        }
+
         // This message may have a radio prefix, and should then be whispered to the resolved radio channel
         if (checkRadioPrefix)
         {
@@ -576,7 +587,9 @@ private void SendEntityEmote(
         bool hideLog = false,
         bool checkEmote = true,
         bool ignoreActionBlocker = false,
-        NetUserId? author = null
+        NetUserId? author = null,
+        LanguagePrototype? languageOverride = null,
+        bool? signLanguage = false
         )
     {
         if (!_actionBlocker.CanEmote(source) && !ignoreActionBlocker)
@@ -586,15 +599,32 @@ private void SendEntityEmote(
         var ent = Identity.Entity(source, EntityManager);
         string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent));
 
+        var language = languageOverride ?? _language.GetLanguage(source);
+
         // Emotes use Identity.Name, since it doesn't actually involve your voice at all.
-        var wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message",
-            ("entityName", name),
-            ("entity", ent),
-            ("message", FormattedMessage.RemoveMarkup(action)));
+        var wrappedMessage = "";
+        var obfuscatedWrappedMessage = "";
+        if (signLanguage == true)
+        {
+            wrappedMessage = Loc.GetString("entity-signlanguage-message",
+                ("entityName", name),
+                ("message", FormattedMessage.EscapeText(action)));
+
+            obfuscatedWrappedMessage = Loc.GetString(_language.ObfuscateSpeech(action, language),
+                ("entityName", name));
+        }
+        else
+        {
+            wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message",
+                ("entityName", name),
+                ("entity", ent),
+                ("message", FormattedMessage.RemoveMarkup(action)));
+
+        }
 
         if (checkEmote)
             TryEmoteChatInput(source, action);
-        SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage: "", source, range, author);
+        SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage, source, range, author, signLanguage: true);
         if (!hideLog)
             if (name != Name(source))
                 _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user} as {name}: {action}");
@@ -749,7 +779,7 @@ private MessageRangeCheckResult MessageRangeCheck(ICommonSession session, ICChat
     /// <summary>
     ///     Sends a chat message to the given players in range of the source entity.
     /// </summary>
-    private void SendInVoiceRange(ChatChannel channel, string name, string message, string wrappedMessage, string obfuscated, string obfuscatedWrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null)
+    private void SendInVoiceRange(ChatChannel channel, string name, string message, string wrappedMessage, string obfuscated, string obfuscatedWrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null, bool? signLanguage = false)
     {
         var language = languageOverride ?? _language.GetLanguage(source);
         foreach (var (session, data) in GetRecipients(source, VoiceRange))
@@ -762,9 +792,17 @@ private void SendInVoiceRange(ChatChannel channel, string name, string message,
                 continue;
             EntityUid listener = session.AttachedEntity.Value;
 
+            // Quickly Checking if the Emote is a real one or Sign Language.
+            var notSignLanguage = false;
+            if (channel == ChatChannel.Emotes)
+            {
+                notSignLanguage = true;
+                if (signLanguage == true)
+                    notSignLanguage = false;
+            }
 
             // If the channel does not support languages, or the entity can understand the message, send the original message, otherwise send the obfuscated version
-            if (channel == ChatChannel.LOOC || channel == ChatChannel.Emotes || _language.CanUnderstand(listener, language.ID))
+            if (channel == ChatChannel.LOOC || notSignLanguage || _language.CanUnderstand(listener, language.ID))
             {
                 _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.Channel, author: author);
             }
diff --git a/Content.Shared/Language/LanguagePrototype.cs b/Content.Shared/Language/LanguagePrototype.cs
index be54b45aa1f..79c17daccd8 100644
--- a/Content.Shared/Language/LanguagePrototype.cs
+++ b/Content.Shared/Language/LanguagePrototype.cs
@@ -16,7 +16,13 @@ public sealed class LanguagePrototype : IPrototype
 
     [DataField("fontSize")]
     public int? FontSize;
-    
+
+    /// <summary>
+    /// 	If true, will mark the language as a SignLanguage and will be handled as such.
+    /// </summary>
+    [DataField("signLanguage")]
+    public bool? SignLanguage;
+
     /// <summary>
     ///     Obfuscation method used by this language. By default, uses <see cref="ObfuscationMethod.Default"/>
     /// </summary>
diff --git a/Resources/Locale/en-US/language/languages.ftl b/Resources/Locale/en-US/language/languages.ftl
index 69c5d0a4a76..209daf92de8 100644
--- a/Resources/Locale/en-US/language/languages.ftl
+++ b/Resources/Locale/en-US/language/languages.ftl
@@ -4,6 +4,9 @@ language-Universal-description = What are you?
 language-GalacticCommon-name = Galactic common
 language-GalacticCommon-description = The standard Galatic language, most commonly used for inter-species communications and legal work.
 
+language-SignLanguage-name = Sign Language
+language-SignLanguage-description = The standard Galactic sign language, used by those that are unable to speak Galactic Common or at all.
+
 language-Bubblish-name = Bubblish
 language-Bubblish-description = The language of Slimes. Being a mixture of bubbling noises and pops it's very difficult to speak for humans without the use of mechanical aids.
 
diff --git a/Resources/Locale/en-US/language/sign-language.ftl b/Resources/Locale/en-US/language/sign-language.ftl
new file mode 100644
index 00000000000..f4548f995c5
--- /dev/null
+++ b/Resources/Locale/en-US/language/sign-language.ftl
@@ -0,0 +1,4 @@
+entity-signlanguage-message = [italic]{$entityName} signs "[BubbleContent]{$message}[/BubbleContent]"[/italic]
+
+language-signlanguage-1 = [italic]{$entityName} signs something.[/italic]
+language-signlanguage-2 = [italic]{$entityName} makes weird hand gestures.[/italic]
diff --git a/Resources/Prototypes/Language/languages.yml b/Resources/Prototypes/Language/languages.yml
index 048fdc6f24c..bec1884fe5c 100644
--- a/Resources/Prototypes/Language/languages.yml
+++ b/Resources/Prototypes/Language/languages.yml
@@ -35,6 +35,15 @@
     - nah
     - wah
 
+- type: language
+  id: SignLanguage
+  signLanguage: true
+  obfuscation:
+    !type:ReplacementObfuscation
+    replacement:
+    - "language-signlanguage-1"
+    - "language-signlanguage-2"
+
 # Spoken by slimes.
 - type: language
   id: Bubblish