diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cdfa8f30..9f685837 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ name: Abaddon CI -on: [ push, pull_request ] +on: [push, pull_request] jobs: msys2: @@ -8,8 +8,8 @@ jobs: runs-on: windows-latest strategy: matrix: - buildtype: [ Debug, RelWithDebInfo, MinSizeRel ] - mindeps: [ false ] + buildtype: [Debug, RelWithDebInfo, MinSizeRel] + mindeps: [false] include: - buildtype: RelWithDebInfo mindeps: true @@ -84,6 +84,7 @@ jobs: mkdir -p ${artifact_dir}/bin ${artifact_dir}/etc/ssl/certs ${artifact_dir}/lib ${artifact_dir}/share/glib-2.0/schemas cd build cp *.exe ../${artifact_dir}/bin + cp -r ./locale/ ../${artifact_dir}/bin cd .. cp /mingw64/etc/ssl/certs/ca-bundle.crt ${artifact_dir}/etc/ssl/certs cp -r /mingw64/lib/gdk-pixbuf-2.0 ${artifact_dir}/lib @@ -122,7 +123,7 @@ jobs: if_false: "${{ matrix.buildtype }}" - name: Upload build (2) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: build-windows-msys2-${{ steps.buildname.outputs.value }} path: build/artifactdir @@ -132,7 +133,7 @@ jobs: runs-on: macos-latest strategy: matrix: - buildtype: [ Debug, RelWithDebInfo ] + buildtype: [Debug, RelWithDebInfo] steps: - uses: actions/checkout@v1 with: @@ -167,7 +168,7 @@ jobs: cp -r "${{ github.workspace }}/res/res" "${artifact_dir}/res" - name: Upload build - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: build-macos-${{ matrix.buildtype }} path: build/artifactdir @@ -177,7 +178,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - buildtype: [ Debug, RelWithDebInfo, MinSizeRel ] + buildtype: [Debug, RelWithDebInfo, MinSizeRel] steps: - uses: actions/checkout@v1 with: @@ -199,6 +200,7 @@ jobs: cmake .. make sudo make install + sudo apt-get install gettext sudo apt-get install libgtkmm-3.0-dev sudo apt-get install libcurl4-gnutls-dev sudo apt-get install libopus-dev @@ -221,11 +223,12 @@ jobs: artifact_dir=${{ runner.workspace }}/artifactdir/abaddon-${{ matrix.buildtype }}-${GITHUB_SHA::7} mkdir -p "${artifact_dir}" cp "${{runner.workspace}}/build/abaddon" "${artifact_dir}/abaddon" + cp -r "${{runner.workspace}}/build/locale" "${artifact_dir}/locale" cp -r "${{ github.workspace }}/res/css" "${artifact_dir}/css" cp -r "${{ github.workspace }}/res/res" "${artifact_dir}/res" - name: Upload build - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: build-linux-${{ matrix.buildtype }} path: ${{ runner.workspace }}/artifactdir diff --git a/CMakeLists.txt b/CMakeLists.txt index 526c8c10..1a49d793 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ find_package(CURL) find_package(ZLIB REQUIRED) find_package(SQLite3 REQUIRED) find_package(gtkmm REQUIRED) +find_package(Intl REQUIRED) set(USE_TLS TRUE) set(USE_OPEN_SSL TRUE) @@ -56,6 +57,9 @@ target_include_directories(abaddon PUBLIC ${GTKMM_INCLUDE_DIRS}) target_include_directories(abaddon PUBLIC ${ZLIB_INCLUDE_DIRS}) target_include_directories(abaddon PUBLIC ${SQLite3_INCLUDE_DIRS}) target_include_directories(abaddon PUBLIC ${NLOHMANN_JSON_INCLUDE_DIRS}) +target_include_directories(abaddon PUBLIC ${Intl_INCLUDE_DIRS}) + +add_subdirectory(po) if (ENABLE_QRCODE_LOGIN) add_library(qrcodegen subprojects/qrcodegen/cpp/qrcodegen.hpp subprojects/qrcodegen/cpp/qrcodegen.cpp) @@ -119,6 +123,10 @@ target_link_libraries(abaddon ${ZLIB_LIBRARY}) target_link_libraries(abaddon ${NLOHMANN_JSON_LIBRARIES}) target_link_libraries(abaddon ${CMAKE_DL_LIBS}) +if (MINGW OR APPLE) + target_link_libraries(abaddon ${Intl_LIBRARIES}) +endif() + target_link_libraries(abaddon CURL::libcurl) include(CheckAtomic) diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt new file mode 100644 index 00000000..90873b1f --- /dev/null +++ b/po/CMakeLists.txt @@ -0,0 +1,37 @@ +find_program(MSGMERGE msgmerge REQUIRED) +find_program(MSGFMT msgfmt REQUIRED) + +set(POT_FILENAME ${CMAKE_CURRENT_SOURCE_DIR}/abaddon.pot) +set(MO_FILENAME abaddon.mo) +set(LOCALE_DIRECTORY ${PROJECT_BINARY_DIR}/locale) + +list(APPEND PO_NAMES pt_BR) + +foreach(PO_NAME IN LISTS PO_NAMES) + list(APPEND PO_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/${PO_NAME}.po) +endforeach() + +# Updates all the translation +foreach(PO_SOURCE PO_NAME IN ZIP_LISTS PO_SOURCES PO_NAMES) + add_custom_target("update-${PO_NAME}" DEPENDS ${PO_SOURCE}) + add_custom_command( + TARGET "update-${PO_NAME}" PRE_BUILD + COMMAND ${MSGMERGE} -U -N ${PO_SOURCE} ${POT_FILENAME} + DEPENDS ${POT_FILENAME} + ) + add_dependencies(abaddon "update-${PO_NAME}") +endforeach() + +# Compiles all the translation files onto locales directory +foreach(PO_SOURCE PO_NAME IN ZIP_LISTS PO_SOURCES PO_NAMES) + file(MAKE_DIRECTORY ${LOCALE_DIRECTORY}/${PO_NAME}/LC_MESSAGES/) + add_custom_command( + OUTPUT ${LOCALE_DIRECTORY}/${PO_NAME}/LC_MESSAGES/${MO_FILENAME} + COMMAND ${MSGFMT} --output-file=${LOCALE_DIRECTORY}/${PO_NAME}/LC_MESSAGES/${MO_FILENAME} + ${PO_SOURCE} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${PO_SOURCE} + ) + add_custom_target("compile-${PO_NAME}" DEPENDS ${LOCALE_DIRECTORY}/${PO_NAME}/LC_MESSAGES/${MO_FILENAME}) + add_dependencies(abaddon "compile-${PO_NAME}") +endforeach() \ No newline at end of file diff --git a/po/POTFILES b/po/POTFILES new file mode 100644 index 00000000..1f26836e --- /dev/null +++ b/po/POTFILES @@ -0,0 +1,34 @@ +src/abaddon.cpp +src/startup.cpp +src/discord/permissions.cpp +src/dialogs/confirm.cpp +src/dialogs/friendpicker.cpp +src/dialogs/setstatus.cpp +src/dialogs/textinput.cpp +src/dialogs/token.cpp +src/dialogs/verificationgate.cpp +src/components/chatinput.cpp +src/components/chatinputindicator.cpp +src/components/chatlist.cpp +src/components/chatmessage.cpp +src/components/chatwindow.cpp +src/components/friendslist.cpp +src/components/ratelimitindicator.cpp +src/components/voiceinfobox.cpp +src/components/channellist/channellisttree.cpp +src/windows/guildsettingswindow.cpp +src/windows/mainwindow.cpp +src/windows/pinnedwindow.cpp +src/windows/profilewindow.cpp +src/windows/threadswindow.cpp +src/windows/voicesettingswindow.cpp +src/windows/profile/mutualguildspane.cpp +src/windows/profile/userinfopane.cpp +src/windows/guildsettings/auditlogpane.cpp +src/windows/guildsettings/banspane.cpp +src/windows/guildsettings/emojispane.cpp +src/windows/guildsettings/infopane.cpp +src/windows/guildsettings/invitespane.cpp +src/windows/guildsettings/memberspane.cpp +src/windows/guildsettings/rolespane.cpp +src/windows/voice/voicewindow.cpp \ No newline at end of file diff --git a/po/TRANSLATING.md b/po/TRANSLATING.md new file mode 100644 index 00000000..4f88632c --- /dev/null +++ b/po/TRANSLATING.md @@ -0,0 +1,46 @@ +# Working with translations + +Translators must first ensure that the tools coming with the gettext package are +installed. If that's not the case install it using your package manager. + +```sh +# On Debian/Ubuntu systems. Use your package manager +sudo apt install gettext +``` + +## Adding new translation files + +Adding new translation files is as easy as issuing a command. In the command +below, replace `LL_CC` for the country code you are translating the project to +and set an appropriate encoding to the country code. + +```sh +msginit -i po/abaddon.pot -o po/LL_CC.po --locale LL_CC[.ENCODING] +``` + +After that, you'll have to append the country code to `PO_NAMES` variable in +[CMakeLists.txt](CMakeLists.txt), build file responsible for compiling and +updating the translations. + +```cmake +# Insert the country code in alphabetical order. +# Replace LL_CC for the country code +list(APPEND PO_NAMES pt_BR LL_CC) +``` + +Then, compile the translation file by simply issuing the build command within +the build directory. Doing this won't only compile but it'll also update the .po +file in case there is any modification made to abaddon.pot. + +```sh +cmake --build build-dir/ +``` + +To ensure that everything is in place, run the program with `LANGUAGE` +environment variable set to the country code you are providing a translation +for: + +```sh +# This snippet assumes that the current directory is the build directory +LANGUAGE=pt_BR ./abaddon +``` diff --git a/po/abaddon.pot b/po/abaddon.pot new file mode 100644 index 00000000..075306a9 --- /dev/null +++ b/po/abaddon.pot @@ -0,0 +1,1960 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-10-11 12:21-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/abaddon.cpp:215 +msgid "css failed parsing (%1)" +msgstr "" + +#: src/abaddon.cpp:231 +msgid "The PNG pixbufloader wasn't detected. Abaddon may not work as a result." +msgstr "" + +#: src/abaddon.cpp:237 +msgid "" +"The GIF pixbufloader wasn't detected. Animations may not display as a result." +msgstr "" + +#: src/abaddon.cpp:252 +msgid "The settings file could not be opened!" +msgstr "" + +#: src/abaddon.cpp:258 +msgid "The emoji file couldn't be loaded!" +msgstr "" + +#: src/abaddon.cpp:264 +msgid "The Discord cache could not be created!" +msgstr "" + +#: src/abaddon.cpp:272 +msgid "The audio engine could not be initialized!" +msgstr "" + +#: src/abaddon.cpp:333 +msgid "Quit" +msgstr "" + +#: src/abaddon.cpp:468 +msgid "Discord rejected your token" +msgstr "" + +#: src/abaddon.cpp:473 +msgid "Lost connection with Discord's gateway. Try reconnecting (code %1)" +msgstr "" + +#: src/abaddon.cpp:483 src/abaddon.cpp:926 +msgid "This thread is archived. Sending a message will unarchive it" +msgstr "" + +#: src/abaddon.cpp:626 +msgid "" +"Cookies could not be fetched. This may increase your chances of being " +"flagged by Discord's anti-spam" +msgstr "" + +#: src/abaddon.cpp:635 +msgid "" +"Build number could not be fetched. This may increase your chances of being " +"flagged by Discord's anti-spam" +msgstr "" + +#: src/abaddon.cpp:652 +msgid "Failed to accept the verification gate." +msgstr "" + +#: src/abaddon.cpp:677 +msgid "Insert Mention" +msgstr "" + +#: src/abaddon.cpp:678 +msgid "Ban" +msgstr "" + +#: src/abaddon.cpp:679 +msgid "Kick" +msgstr "" + +#: src/abaddon.cpp:680 src/components/chatlist.cpp:298 +#: src/windows/guildsettings/banspane.cpp:13 +#: src/windows/guildsettings/emojispane.cpp:18 +msgid "Copy ID" +msgstr "" + +#: src/abaddon.cpp:681 +msgid "Go to DM" +msgstr "" + +#: src/abaddon.cpp:682 src/windows/guildsettingswindow.cpp:66 +msgid "Roles" +msgstr "" + +#: src/abaddon.cpp:683 +msgid "View Profile" +msgstr "" + +#: src/abaddon.cpp:684 +msgid "Remove From Group" +msgstr "" + +#: src/abaddon.cpp:1002 +msgid "Are you sure you want to leave %1?" +msgstr "" + +#: src/abaddon.cpp:1012 +msgid "Are you sure you want to kick %1?" +msgstr "" + +#: src/abaddon.cpp:1022 +msgid "Are you sure you want to ban %1?" +msgstr "" + +#: src/abaddon.cpp:1119 +msgid "css failed to load (%1)" +msgstr "" + +#: src/startup.cpp:14 +msgid "Getting connection info..." +msgstr "" + +#: src/discord/permissions.cpp:16 +msgid "None" +msgstr "" + +#: src/discord/permissions.cpp:18 +msgid "Create Invite" +msgstr "" + +#: src/discord/permissions.cpp:20 +msgid "Kick Members" +msgstr "" + +#: src/discord/permissions.cpp:22 +msgid "Ban Members" +msgstr "" + +#: src/discord/permissions.cpp:24 +msgid "Administrator" +msgstr "" + +#: src/discord/permissions.cpp:26 +msgid "Manage Channels" +msgstr "" + +#: src/discord/permissions.cpp:28 +msgid "Manage Server" +msgstr "" + +#: src/discord/permissions.cpp:30 +msgid "Add Reactions" +msgstr "" + +#: src/discord/permissions.cpp:32 +msgid "View Audit Log" +msgstr "" + +#: src/discord/permissions.cpp:34 +msgid "Use Priority Speaker" +msgstr "" + +#: src/discord/permissions.cpp:36 +msgid "Video" +msgstr "" + +#: src/discord/permissions.cpp:38 +msgid "View Channels" +msgstr "" + +#: src/discord/permissions.cpp:40 +msgid "Send Messages" +msgstr "" + +#: src/discord/permissions.cpp:42 +msgid "Use TTS" +msgstr "" + +#: src/discord/permissions.cpp:44 +msgid "Manage Messages" +msgstr "" + +#: src/discord/permissions.cpp:46 +msgid "Embed Links" +msgstr "" + +#: src/discord/permissions.cpp:48 +msgid "Attach Files" +msgstr "" + +#: src/discord/permissions.cpp:50 +msgid "Read Message History" +msgstr "" + +#: src/discord/permissions.cpp:52 +msgid "Mention @everyone" +msgstr "" + +#: src/discord/permissions.cpp:54 +msgid "Use External Emojis" +msgstr "" + +#: src/discord/permissions.cpp:56 +msgid "View Server Insights" +msgstr "" + +#: src/discord/permissions.cpp:58 +msgid "Connect to Voice" +msgstr "" + +#: src/discord/permissions.cpp:60 +msgid "Speak in Voice" +msgstr "" + +#: src/discord/permissions.cpp:62 +msgid "Mute Members" +msgstr "" + +#: src/discord/permissions.cpp:64 +msgid "Deafen Members" +msgstr "" + +#: src/discord/permissions.cpp:66 +msgid "Move Members" +msgstr "" + +#: src/discord/permissions.cpp:68 +msgid "Use Voice Activation" +msgstr "" + +#: src/discord/permissions.cpp:70 +msgid "Change Nickname" +msgstr "" + +#: src/discord/permissions.cpp:72 +msgid "Manage Nicknames" +msgstr "" + +#: src/discord/permissions.cpp:74 +msgid "Manage Roles" +msgstr "" + +#: src/discord/permissions.cpp:76 +msgid "Manage Webhooks" +msgstr "" + +#: src/discord/permissions.cpp:78 +msgid "Manage Expressions" +msgstr "" + +#: src/discord/permissions.cpp:80 +msgid "Use Application Commands" +msgstr "" + +#: src/discord/permissions.cpp:82 +msgid "Manage Events" +msgstr "" + +#: src/discord/permissions.cpp:84 +msgid "Manage Threads" +msgstr "" + +#: src/discord/permissions.cpp:86 +msgid "Create Public Threads" +msgstr "" + +#: src/discord/permissions.cpp:88 +msgid "Create Private Threads" +msgstr "" + +#: src/discord/permissions.cpp:90 +msgid "Use External Stickers" +msgstr "" + +#: src/discord/permissions.cpp:92 +msgid "Send Messages In Threads" +msgstr "" + +#: src/discord/permissions.cpp:94 +msgid "Use Activities" +msgstr "" + +#: src/discord/permissions.cpp:96 +msgid "Timeout Members" +msgstr "" + +#: src/discord/permissions.cpp:100 +msgid "Use Soundboard" +msgstr "" + +#: src/discord/permissions.cpp:102 +msgid "Create Expressions" +msgstr "" + +#: src/discord/permissions.cpp:104 +msgid "Create Events" +msgstr "" + +#: src/discord/permissions.cpp:106 +msgid "Use External Sounds" +msgstr "" + +#: src/discord/permissions.cpp:108 +msgid "Send Voice Messages" +msgstr "" + +#: src/discord/permissions.cpp:112 +msgid "Set Voice Channel Status" +msgstr "" + +#: src/discord/permissions.cpp:114 +msgid "Unknown Permission" +msgstr "" + +#: src/discord/permissions.cpp:123 +msgid "Allows members to invite new people to this server." +msgstr "" + +#: src/discord/permissions.cpp:125 +msgid "" +"Allows members to remove other members from this server. Kicked members will " +"be able to rejoin if they have another invite." +msgstr "" + +#: src/discord/permissions.cpp:127 +msgid "Allows members to permanently ban other members from this server." +msgstr "" + +#: src/discord/permissions.cpp:129 +msgid "" +"Members with this permission will have every permission and will also bypass " +"all channel specific permissions or restrictions (for example, these members " +"would get access to all private channels). This is a dangerous permission to " +"grant." +msgstr "" + +#: src/discord/permissions.cpp:131 +msgid "Allows members to create, edit, or delete channels." +msgstr "" + +#: src/discord/permissions.cpp:133 +msgid "" +"Allows members to change this server's name, switch regions, and add bots to " +"this server." +msgstr "" + +#: src/discord/permissions.cpp:135 +msgid "" +"Allows members to add new emoji reactions to a message. If this permission " +"is disabled, members can still react using any existing reactions on a " +"message." +msgstr "" + +#: src/discord/permissions.cpp:137 +msgid "" +"Allows members to view a record of who made which changes in this server." +msgstr "" + +#: src/discord/permissions.cpp:139 +msgid "" +"Allows members to be more easily heard in voice channels. When activated, " +"the volume of others without this permission will be automatically lowered. " +"Priority Speaker is activated by using the Push to Talk (Priority) keybind." +msgstr "" + +#: src/discord/permissions.cpp:141 +msgid "" +"Allows members to share their video, screen share, or stream a game in this " +"server." +msgstr "" + +#: src/discord/permissions.cpp:143 +msgid "" +"Allows members to view channels by default (excluding private channels)." +msgstr "" + +#: src/discord/permissions.cpp:145 +msgid "Allows members to send messages in text channels." +msgstr "" + +#: src/discord/permissions.cpp:147 +msgid "" +"Allows members to send text-to-speech messages by starting a message with /" +"tts. These messages can be heard by anyone focused on this channel." +msgstr "" + +#: src/discord/permissions.cpp:149 +msgid "Allows members to delete messages by other members or pin any message." +msgstr "" + +#: src/discord/permissions.cpp:151 +msgid "" +"Allows links that members share to show embedded content in text channels." +msgstr "" + +#: src/discord/permissions.cpp:153 +msgid "Allows members to upload files or media in text channels." +msgstr "" + +#: src/discord/permissions.cpp:155 +msgid "" +"Allows members to read previous messages sent in channels. If this " +"permission is disabled, members only see messages sent when they are online " +"and focused on that channel." +msgstr "" + +#: src/discord/permissions.cpp:157 +msgid "" +"Allows members to use @everyone (everyone in the server) or @here (only " +"online members in that channel). They can also @mention all roles, even if " +"the role's \"Allow anyone to mention this role\" permission is disabled." +msgstr "" + +#: src/discord/permissions.cpp:159 +msgid "" +"Allows members to use emoji from other servers, if they're a Discord Nitro " +"member." +msgstr "" + +#: src/discord/permissions.cpp:161 +msgid "" +"Allows members to view Server Insights, which shows data on community " +"growth, engagement, and more." +msgstr "" + +#: src/discord/permissions.cpp:163 +msgid "Allows members to join voice channels and hear others." +msgstr "" + +#: src/discord/permissions.cpp:165 +msgid "" +"Allows members to talk in voice channels. If this permission is disabled, " +"members are default muted until somebody with the \"Mute Members\" " +"permission unmutes them." +msgstr "" + +#: src/discord/permissions.cpp:167 +msgid "Allows members to mute other members in voice channels for everyone." +msgstr "" + +#: src/discord/permissions.cpp:169 +msgid "" +"Allows members to deafen other members in voice channels, which means they " +"won't be able to speak or hear others." +msgstr "" + +#: src/discord/permissions.cpp:171 +msgid "" +"Allows members to move other members between voice channels that the member " +"with the permission has access to." +msgstr "" + +#: src/discord/permissions.cpp:173 +msgid "" +"Allows members to speak in voice channels by simply talking. If this " +"permission is disabled, members are required to use Push-to-talk. Good for " +"controlling background noise or noisy members." +msgstr "" + +#: src/discord/permissions.cpp:175 +msgid "" +"Allows members to change their own nickname, a custom name for just this " +"server." +msgstr "" + +#: src/discord/permissions.cpp:177 +msgid "Allows members to change the nicknames of other members." +msgstr "" + +#: src/discord/permissions.cpp:179 +msgid "" +"Allows members to create new roles and edit or delete roles lower than their " +"highest role. Also allows members to change permissions of individual " +"channels that they have access to." +msgstr "" + +#: src/discord/permissions.cpp:181 +msgid "" +"Allows members to create, edit, or delete webhooks, which can post messages " +"from other apps or sites into this server." +msgstr "" + +#: src/discord/permissions.cpp:183 +msgid "" +"Allows members to add or remove custom emoji, stickers, and sounds in this " +"server." +msgstr "" + +#: src/discord/permissions.cpp:185 +msgid "" +"Allows members to use commands from applications, including slash commands " +"and context menu commands." +msgstr "" + +#: src/discord/permissions.cpp:187 +msgid "Allows members to edit and cancel events." +msgstr "" + +#: src/discord/permissions.cpp:189 +msgid "" +"Allows members to rename, delete, close, and turn on slow mode for threads. " +"They can also view private threads." +msgstr "" + +#: src/discord/permissions.cpp:191 +msgid "Allows members to create threads that everyone in a channel can view." +msgstr "" + +#: src/discord/permissions.cpp:193 +msgid "Allows members to create invite-only threads." +msgstr "" + +#: src/discord/permissions.cpp:195 +msgid "" +"Allows members to use stickers from other servers, if they're a Discord " +"Nitro member." +msgstr "" + +#: src/discord/permissions.cpp:197 +msgid "Allows members to send messages in threads." +msgstr "" + +#: src/discord/permissions.cpp:199 +msgid "Allows members to use Activities in this server." +msgstr "" + +#: src/discord/permissions.cpp:201 +msgid "" +"When you put a user in timeout they will not be able to send messages in " +"chat, reply within threads, react to messages, or speak in voice or Stage " +"channels." +msgstr "" + +#: src/discord/permissions.cpp:205 +msgid "Allows members to send sounds from server soundboard." +msgstr "" + +#: src/discord/permissions.cpp:207 +msgid "" +"Allows members to add custom emoji, stickers, and sounds in this server." +msgstr "" + +#: src/discord/permissions.cpp:209 +msgid "Allows members to create events." +msgstr "" + +#: src/discord/permissions.cpp:211 +msgid "" +"Allows members to use sounds from other servers, if they're a Discord Nitro " +"member." +msgstr "" + +#: src/discord/permissions.cpp:213 +msgid "Allows members to send voice messages." +msgstr "" + +#: src/discord/permissions.cpp:217 +msgid "Allows members to create and edit voice channel status." +msgstr "" + +#: src/dialogs/confirm.cpp:6 +msgid "Confirm" +msgstr "" + +#: src/dialogs/confirm.cpp:9 src/dialogs/friendpicker.cpp:15 +#: src/dialogs/setstatus.cpp:26 src/dialogs/textinput.cpp:12 +#: src/dialogs/token.cpp:16 src/components/friendslist.cpp:293 +msgid "Cancel" +msgstr "" + +#: src/dialogs/confirm.cpp:15 +msgid "Are you sure?" +msgstr "" + +#: src/dialogs/friendpicker.cpp:8 +msgid "Pick a friend" +msgstr "" + +#: src/dialogs/setstatus.cpp:23 src/windows/mainwindow.cpp:268 +msgid "Set Status" +msgstr "" + +#: src/dialogs/setstatus.cpp:34 src/dialogs/setstatus.cpp:38 +#: src/components/friendslist.cpp:27 +msgid "Online" +msgstr "" + +#: src/dialogs/setstatus.cpp:35 +msgid "Do Not Disturb" +msgstr "" + +#: src/dialogs/setstatus.cpp:36 +msgid "Away" +msgstr "" + +#: src/dialogs/setstatus.cpp:37 +msgid "Invisible" +msgstr "" + +#: src/dialogs/setstatus.cpp:40 +msgid "Playing" +msgstr "" + +#: src/dialogs/setstatus.cpp:41 +msgid "Streaming" +msgstr "" + +#: src/dialogs/setstatus.cpp:42 +msgid "Listening to" +msgstr "" + +#: src/dialogs/setstatus.cpp:43 +msgid "Watching" +msgstr "" + +#: src/dialogs/setstatus.cpp:44 src/dialogs/setstatus.cpp:46 +msgid "Custom" +msgstr "" + +#: src/dialogs/setstatus.cpp:45 +msgid "Competing in" +msgstr "" + +#: src/dialogs/setstatus.cpp:56 +msgid "How are you, %1?" +msgstr "" + +#: src/dialogs/setstatus.cpp:58 +msgid "Status" +msgstr "" + +#: src/dialogs/setstatus.cpp:60 +msgid "Activity" +msgstr "" + +#: src/dialogs/token.cpp:13 src/windows/mainwindow.cpp:262 +msgid "Set Token" +msgstr "" + +#: src/dialogs/verificationgate.cpp:8 +msgid "Verification Required" +msgstr "" + +#: src/dialogs/verificationgate.cpp:14 src/components/friendslist.cpp:258 +#: src/windows/voice/voicewindow.cpp:29 +msgid "Accept" +msgstr "" + +#: src/components/chatinput.cpp:143 +msgid "Choose file" +msgstr "" + +#: src/components/chatinput.cpp:389 src/components/friendslist.cpp:287 +msgid "Remove" +msgstr "" + +#: src/components/chatinput.cpp:394 +msgid "Change Filename" +msgstr "" + +#: src/components/chatinput.cpp:396 +msgid "Enter new filename for attachment" +msgstr "" + +#: src/components/chatinput.cpp:396 +msgid "Enter filename" +msgstr "" + +#: src/components/chatinput.cpp:404 +msgid "Change Alt-Text" +msgstr "" + +#: src/components/chatinput.cpp:406 +msgid "Enter description (alt-text) for attachment" +msgstr "" + +#: src/components/chatinput.cpp:406 +msgid "Enter alt-text" +msgstr "" + +#: src/components/chatinputindicator.cpp:119 +msgid "%1 is typing..." +msgstr "" + +#: src/components/chatinputindicator.cpp:121 +msgid "%1 and %2 are typing" +msgstr "" + +#: src/components/chatinputindicator.cpp:126 +msgid "%1, %2, %3 and %4 are typing..." +msgstr "" + +#: src/components/chatinputindicator.cpp:133 +msgid "Several people are typing..." +msgstr "" + +#: src/components/chatlist.cpp:305 +msgid "Delete Message" +msgstr "" + +#: src/components/chatlist.cpp:312 +msgid "Edit Message" +msgstr "" + +#: src/components/chatlist.cpp:319 +msgid "Copy Content" +msgstr "" + +#: src/components/chatlist.cpp:328 +msgid "Reply To" +msgstr "" + +#: src/components/chatlist.cpp:335 +msgid "Unpin" +msgstr "" + +#: src/components/chatlist.cpp:341 +msgid "Pin" +msgstr "" + +#: src/components/chatmessage.cpp:15 +msgid "Copy Link" +msgstr "" + +#: src/components/chatmessage.cpp:146 +msgid "deleted" +msgstr "" + +#: src/components/chatmessage.cpp:148 +msgid "edited" +msgstr "" + +#: src/components/chatmessage.cpp:202 +msgid "boosted server" +msgstr "" + +#: src/components/chatmessage.cpp:205 +msgid "user joined" +msgstr "" + +#: src/components/chatmessage.cpp:208 +msgid "message pinned" +msgstr "" + +#: src/components/chatmessage.cpp:218 +msgid "used %1 with %2" +msgstr "" + +#: src/components/chatmessage.cpp:233 +msgid "" +"%1 added %2" +msgstr "" + +#: src/components/chatmessage.cpp:243 +msgid "" +"%1 left" +msgstr "" + +#: src/components/chatmessage.cpp:245 +msgid "" +"%1 removed %2" +msgstr "" + +#: src/components/chatmessage.cpp:252 +msgid "%1 changed the name to %2" +msgstr "" + +#: src/components/chatmessage.cpp:257 +msgid "%1 changed the channel icon" +msgstr "" + +#: src/components/chatmessage.cpp:265 +msgid "" +"%1 just boosted the server %2 times! %3 has " +"achieved Level %4!" +msgstr "" + +#: src/components/chatmessage.cpp:275 +msgid "" +"%1 has added %2 to this channel. Its most " +"important updates will show up here." +msgstr "" + +#: src/components/chatmessage.cpp:281 +msgid "started a call" +msgstr "" + +#: src/components/chatmessage.cpp:284 +msgid "" +"This server has been removed from Server Discovery because it no longer " +"passes all the requirements." +msgstr "" + +#: src/components/chatmessage.cpp:287 +msgid "" +"This server is eligible for Server Discovery again and has been " +"automatically relisted!" +msgstr "" + +#: src/components/chatmessage.cpp:290 +msgid "" +"This server has failed Discovery activity requirements for 1 week. If this " +"server fails for 4 weeks in a row, it will be automatically removed from " +"Discovery." +msgstr "" + +#: src/components/chatmessage.cpp:293 +msgid "" +"This server has failed Discovery activity requirements for 3 weeks in a row. " +"If this server fails for 1 more week, it will be removed from Discovery." +msgstr "" + +#: src/components/chatmessage.cpp:299 +msgid "%1 started a thread: " +msgstr "" + +#: src/components/chatmessage.cpp:306 +msgid "%1 started a thread: %2" +msgstr "" + +#: src/components/chatmessage.cpp:713 src/components/chatmessage.cpp:736 +#: src/windows/guildsettings/auditlogpane.cpp:44 +msgid "Unknown User" +msgstr "" + +#: src/components/chatmessage.cpp:729 +msgid "%1 used /%2" +msgstr "" + +#: src/components/chatmessage.cpp:740 +msgid "deleted message" +msgstr "" + +#: src/components/chatmessage.cpp:746 +msgid "attachment" +msgstr "" + +#: src/components/chatmessage.cpp:748 +msgid "embed" +msgstr "" + +#: src/components/chatmessage.cpp:768 +msgid "reply unavailable" +msgstr "" + +#: src/components/chatwindow.cpp:333 +msgid "Replying to %1" +msgstr "" + +#: src/components/chatwindow.cpp:335 +msgid "Replying..." +msgstr "" + +#: src/components/chatwindow.cpp:355 +msgid "Editing..." +msgstr "" + +#: src/components/friendslist.cpp:26 src/windows/mainwindow.cpp:290 +msgid "Friends" +msgstr "" + +#: src/components/friendslist.cpp:28 +msgid "Pending" +msgstr "" + +#: src/components/friendslist.cpp:29 +msgid "Blocked" +msgstr "" + +#: src/components/friendslist.cpp:114 +msgid "Failed to accept" +msgstr "" + +#: src/components/friendslist.cpp:129 +msgid "Are you sure you want to unblock %1?" +msgstr "" + +#: src/components/friendslist.cpp:132 +msgid "Are you sure you want to remove %1?" +msgstr "" + +#: src/components/friendslist.cpp:135 +msgid "Are you sure you want to ignore %1?" +msgstr "" + +#: src/components/friendslist.cpp:138 +msgid "Are you sure you want to cancel your request to %1?" +msgstr "" + +#: src/components/friendslist.cpp:146 +msgid "Failed to remove user" +msgstr "" + +#: src/components/friendslist.cpp:195 +msgid "Add a Friend" +msgstr "" + +#: src/components/friendslist.cpp:197 +msgid "Add" +msgstr "" + +#: src/components/friendslist.cpp:207 +msgid "Enter a Username#1234" +msgstr "" + +#: src/components/friendslist.cpp:220 +msgid "Invalid input" +msgstr "" + +#: src/components/friendslist.cpp:230 +msgid "Hang on..." +msgstr "" + +#: src/components/friendslist.cpp:235 +msgid "Success!" +msgstr "" + +#: src/components/friendslist.cpp:237 +msgid "Failed: %1" +msgstr "" + +#: src/components/friendslist.cpp:290 +msgid "Ignore" +msgstr "" + +#: src/components/friendslist.cpp:331 +msgid "Incoming Friend Request" +msgstr "" + +#: src/components/friendslist.cpp:334 +msgid "Outgoing Friend Request" +msgstr "" + +#: src/components/ratelimitindicator.cpp:87 +msgid "You may bypass slowmode." +msgstr "" + +#: src/components/ratelimitindicator.cpp:92 +#, c-format +msgid "%1s" +msgstr "" + +#: src/components/ratelimitindicator.cpp:95 +msgid "Slowmode is enabled. Members can send one message every %1 seconds" +msgstr "" + +#: src/components/voiceinfobox.cpp:33 src/components/voiceinfobox.cpp:34 +msgid "You shouldn't see me" +msgstr "" + +#: src/components/voiceinfobox.cpp:49 +msgid "Connecting" +msgstr "" + +#: src/components/voiceinfobox.cpp:52 +msgid "Establishing connection" +msgstr "" + +#: src/components/voiceinfobox.cpp:55 +msgid "Connected" +msgstr "" + +#: src/components/voiceinfobox.cpp:59 +msgid "Disconnected" +msgstr "" + +#: src/components/voiceinfobox.cpp:62 src/components/voiceinfobox.cpp:118 +msgid "Unknown" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:19 +#: src/components/channellist/channellisttree.cpp:23 +#: src/components/channellist/channellisttree.cpp:24 +#: src/components/channellist/channellisttree.cpp:37 +#: src/components/channellist/channellisttree.cpp:44 +msgid "_Copy ID" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:20 +msgid "View _Settings" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:21 +#: src/components/channellist/channellisttree.cpp:45 +msgid "_Leave" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:22 +#: src/components/channellist/channellisttree.cpp:25 +#: src/components/channellist/channellisttree.cpp:35 +#: src/components/channellist/channellisttree.cpp:48 +msgid "Mark as _Read" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:27 +#: src/components/channellist/channellisttree.cpp:28 +msgid "Open in New _Tab" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:31 +#: src/components/channellist/channellisttree.cpp:33 +msgid "_Join" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:32 +#: src/components/channellist/channellisttree.cpp:34 +msgid "_Disconnect" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:36 +msgid "Open _Chat" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:41 +msgid "Join _Voice" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:42 +msgid "_Disconnect Voice" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:46 +msgid "_Archive" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:47 +msgid "_Unarchive" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:259 +msgid "Are you sure you want to leave this group DM?" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:297 +msgid "Are you sure you want to leave this thread?" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:1199 +msgid "Direct Messages" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:1371 +msgid "Close" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:1371 +msgid "Leave" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:1425 +#: src/components/channellist/channellisttree.cpp:1439 +#: src/components/channellist/channellisttree.cpp:1503 +#: src/components/channellist/channellisttree.cpp:1528 +msgid "Unmute" +msgstr "" + +#: src/components/channellist/channellisttree.cpp:1427 +#: src/components/channellist/channellisttree.cpp:1441 +#: src/components/channellist/channellisttree.cpp:1505 +#: src/components/channellist/channellisttree.cpp:1530 +#: src/windows/voice/voicewindow.cpp:22 +msgid "Mute" +msgstr "" + +#: src/windows/guildsettingswindow.cpp:64 +msgid "Info" +msgstr "" + +#: src/windows/guildsettingswindow.cpp:65 src/windows/mainwindow.cpp:298 +msgid "Members" +msgstr "" + +#: src/windows/guildsettingswindow.cpp:67 +msgid "Bans" +msgstr "" + +#: src/windows/guildsettingswindow.cpp:69 +msgid "Invites" +msgstr "" + +#: src/windows/guildsettingswindow.cpp:70 +msgid "Emojis" +msgstr "" + +#: src/windows/guildsettingswindow.cpp:72 +msgid "Audit Log" +msgstr "" + +#: src/windows/mainwindow.cpp:258 +msgid "Connect" +msgstr "" + +#: src/windows/mainwindow.cpp:260 src/windows/voice/voicewindow.cpp:27 +msgid "Disconnect" +msgstr "" + +#: src/windows/mainwindow.cpp:263 +msgid "Login with QR Code" +msgstr "" + +#: src/windows/mainwindow.cpp:266 +msgid "Not compiled with support" +msgstr "" + +#: src/windows/mainwindow.cpp:270 +msgid "Add user to DM" +msgstr "" + +#: src/windows/mainwindow.cpp:279 +msgid "File" +msgstr "" + +#: src/windows/mainwindow.cpp:281 +msgid "Reload CSS" +msgstr "" + +#: src/windows/mainwindow.cpp:282 +msgid "Clear file cache" +msgstr "" + +#: src/windows/mainwindow.cpp:283 +msgid "Dump ready message" +msgstr "" + +#: src/windows/mainwindow.cpp:288 src/windows/voice/voicewindow.cpp:32 +msgid "View" +msgstr "" + +#: src/windows/mainwindow.cpp:291 +msgid "Pins" +msgstr "" + +#: src/windows/mainwindow.cpp:292 +msgid "Threads" +msgstr "" + +#: src/windows/mainwindow.cpp:293 +msgid "Mark Server as Read" +msgstr "" + +#: src/windows/mainwindow.cpp:295 +msgid "Channels" +msgstr "" + +#: src/windows/mainwindow.cpp:302 +msgid "Go Back" +msgstr "" + +#: src/windows/mainwindow.cpp:303 +msgid "Go Forward" +msgstr "" + +#: src/windows/pinnedwindow.cpp:15 +msgid "#%1 - Pinned Messages" +msgstr "" + +#: src/windows/pinnedwindow.cpp:17 +msgid "Pinned Messages" +msgstr "" + +#: src/windows/profilewindow.cpp:80 +msgid "User Info" +msgstr "" + +#: src/windows/profilewindow.cpp:81 +msgid "Mutual Servers" +msgstr "" + +#: src/windows/profilewindow.cpp:82 +msgid "Mutual Friends" +msgstr "" + +#: src/windows/profilewindow.cpp:113 +msgid "Originally known as %1" +msgstr "" + +#: src/windows/threadswindow.cpp:9 +msgid "Public" +msgstr "" + +#: src/windows/threadswindow.cpp:10 +msgid "Private" +msgstr "" + +#: src/windows/threadswindow.cpp:16 +msgid "#%1 - Threads" +msgstr "" + +#: src/windows/threadswindow.cpp:32 +msgid "Active Threads" +msgstr "" + +#: src/windows/threadswindow.cpp:33 +msgid "Archived Threads" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:21 +#: src/windows/voicesettingswindow.cpp:53 +msgid "Voice" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:22 +#: src/windows/voicesettingswindow.cpp:54 +msgid "Music" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:23 +msgid "Restricted" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:25 +msgid "" +"Sets the coding mode for the Opus encoder\n" +"Voice - Optimize for voice quality\n" +"Music - Optimize for non-voice signals incl. music\n" +"Restricted - Optimize for non-voice, low latency. Not recommended" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:52 +msgid "Auto" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:56 +msgid "" +"Signal hint. Tells Opus what the current signal is\n" +"Auto - Let Opus figure it out\n" +"Voice - Tell Opus it's a voice signal\n" +"Music - Tell Opus it's a music signal" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:130 +msgid "Coding Mode" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:131 +msgid "Signal Hint" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:132 +msgid "Bitrate" +msgstr "" + +#: src/windows/voicesettingswindow.cpp:133 +#: src/windows/voice/voicewindow.cpp:181 +msgid "Gain" +msgstr "" + +#: src/windows/profile/mutualguildspane.cpp:38 +msgid "Unknown Server" +msgstr "" + +#: src/windows/profile/userinfopane.cpp:144 +msgid "NOTE" +msgstr "" + +#: src/windows/profile/userinfopane.cpp:190 +msgid "ABOUT ME" +msgstr "" + +#: src/windows/profile/userinfopane.cpp:216 +msgid "Failed to set note" +msgstr "" + +#: src/windows/profile/userinfopane.cpp:238 +#: src/windows/guildsettings/memberspane.cpp:214 +msgid "Account created: " +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:55 +msgid "%1 made changes to %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:61 +msgid "Set the server icon" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:66 +msgid "Set the server name to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:69 +msgid "Set the server name" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:76 +msgid "%1 created a voice channel #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:79 +msgid "%1 created a text channel #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:87 +#: src/windows/guildsettings/auditlogpane.cpp:477 +msgid "Set the name to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:91 +#: src/windows/guildsettings/auditlogpane.cpp:128 +msgid "Marked the channel as NSFW" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:93 +#: src/windows/guildsettings/auditlogpane.cpp:130 +msgid "Unmarked the channel as NSFW" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:100 +msgid "%1 made changes to #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:103 +msgid "%1 made changes to <#%2>" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:113 +#: src/windows/guildsettings/auditlogpane.cpp:384 +#: src/windows/guildsettings/auditlogpane.cpp:503 +msgid "Changed the name from %1 to %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:117 +#: src/windows/guildsettings/auditlogpane.cpp:254 +#: src/windows/guildsettings/auditlogpane.cpp:346 +msgid "Changed the name to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:122 +msgid "Changed the topic to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:124 +msgid "Cleared the topic" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:135 +#: src/windows/guildsettings/auditlogpane.cpp:486 +#: src/windows/guildsettings/auditlogpane.cpp:511 +msgid "Disabled slowmode" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:137 +#: src/windows/guildsettings/auditlogpane.cpp:488 +#: src/windows/guildsettings/auditlogpane.cpp:513 +msgid "Set slowmode to %1 seconds" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:143 +msgid "%1 removed #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:149 +msgid "%1 created channel overrides for #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:151 +msgid "%1 created channel overrides for <#%2>" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:158 +msgid "%1 updated channel overrides for #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:160 +msgid "%1 updated channel overrides for <#%2>" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:167 +msgid "%1 removed channel overrides for #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:169 +msgid "%1 removed channel overrides for <#%2>" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:174 +msgid "%1 kicked %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:177 +msgid "%1 pruned %2 members" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:178 +msgid "For %1 days of inactivity" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:182 +msgid "%1 banned %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:186 +msgid "%1 removed the ban for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:190 +msgid "%1 updated %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:195 +msgid "Deafened them" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:195 +msgid "Undeafened them" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:197 +msgid "Muted them" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:197 +msgid "Unmuted them" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:199 +msgid "Set their nickname to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:205 +msgid "%1 updated roles for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:210 +msgid "Removed a role %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:212 +msgid "Added a role %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:222 +msgid "%1 moved a user to %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:225 +msgid "%1 moved %2 users to %3" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:231 +msgid "%1 disconnected %2 users from voice" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:237 +msgid "%1 added %2 to the server" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:242 +msgid "%1 created the role %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:247 +msgid "%1 updated the role %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:258 +msgid "Removed the color" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:260 +msgid "Set the color to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:263 +msgid "Updated the permissions" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:265 +msgid "Mentionable" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:265 +msgid "Not mentionable" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:267 +msgid "Not hoisted" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:267 +msgid "Hoisted" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:275 +msgid "%1 deleted the role %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:280 +msgid "%1 created an invite %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:286 +msgid "For channel %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:291 +msgid "Which has unlimited uses" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:293 +msgid "Which has %1 uses" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:297 +msgid "With temporary on" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:299 +msgid "With temporary off" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:307 +msgid "%1 deleted an invite %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:312 +msgid "%1 created the webhook %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:320 +msgid "With channel #%1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:335 +msgid "%1 updated the webhook %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:340 +msgid "%1 updated a webhook" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:349 +msgid "Changed the avatar" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:354 +msgid "Changed the channel to #%1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:357 +msgid "Changed the channel" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:366 +msgid "%1 deleted the webhook %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:373 +msgid "%1 created the emoji %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:380 +msgid "%1 updated the emoji %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:391 +msgid "%1 deleted the emoji %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:402 +msgid "%1 deleted %2 messages in #%3" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:406 +msgid "%1 deleted %2 messages" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:414 +msgid "%1 pinned a message by %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:420 +msgid "%1 unpinned a message by %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:425 +msgid "%1 started the stage for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:433 +#: src/windows/guildsettings/auditlogpane.cpp:453 +msgid "Set the topic to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:438 +#: src/windows/guildsettings/auditlogpane.cpp:458 +msgid "Set the privacy level to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:445 +msgid "%1 updated the stage for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:465 +msgid "%1 ended the stage for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:471 +msgid "%1 created a thread %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:480 +#: src/windows/guildsettings/auditlogpane.cpp:517 +msgid "Archived the thread" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:480 +#: src/windows/guildsettings/auditlogpane.cpp:517 +msgid "Unarchived the thread" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:482 +#: src/windows/guildsettings/auditlogpane.cpp:507 +msgid "Set auto archive duration to %1 minutes" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:490 +#: src/windows/guildsettings/auditlogpane.cpp:515 +msgid "Locked the thread, restricting it to only be unarchived by moderators" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:490 +#: src/windows/guildsettings/auditlogpane.cpp:515 +msgid "Unlocked the thread, allowing it to be unarchived by non-moderators" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:496 +msgid "%1 made changes to the thread %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:521 +msgid "%1 deleted the thread %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:525 +msgid "Unknown action" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:533 +msgid "Reason: %1" +msgstr "" + +#: src/windows/guildsettings/banspane.cpp:12 +msgid "Unban" +msgstr "" + +#: src/windows/guildsettings/banspane.cpp:31 +msgid "" +"You do not have permission to see bans. However, bans made while you are " +"connected will appear here" +msgstr "" + +#: src/windows/guildsettings/banspane.cpp:55 +msgid "User" +msgstr "" + +#: src/windows/guildsettings/banspane.cpp:56 +msgid "Reason" +msgstr "" + +#: src/windows/guildsettings/banspane.cpp:100 +msgid "Failed to unban user" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:17 +#: src/windows/guildsettings/invitespane.cpp:12 +msgid "Delete" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:19 +msgid "Copy Emoji URL" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:20 +msgid "Open in Browser" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:48 +#: src/windows/guildsettings/memberspane.cpp:64 +#: src/windows/guildsettings/rolespane.cpp:118 +msgid "Filter" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:68 +msgid "Emoji" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:76 +#: src/windows/guildsettings/emojispane.cpp:98 +msgid "Name" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:100 +msgid "Creator" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:101 +msgid "Is Animated?" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:132 +#: src/windows/guildsettings/emojispane.cpp:136 +#: src/windows/guildsettings/emojispane.cpp:138 +#: src/windows/guildsettings/emojispane.cpp:222 +#: src/windows/guildsettings/emojispane.cpp:230 +#: src/windows/guildsettings/invitespane.cpp:75 +msgid "Yes" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:132 +#: src/windows/guildsettings/emojispane.cpp:134 +#: src/windows/guildsettings/emojispane.cpp:136 +#: src/windows/guildsettings/invitespane.cpp:75 +msgid "No" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:186 +msgid "Failed to set emoji name" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:206 +msgid "Are you sure you want to delete %1?" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:209 +msgid "Failed to delete emoji" +msgstr "" + +#: src/windows/guildsettings/infopane.cpp:15 +msgid "Guild name" +msgstr "" + +#: src/windows/guildsettings/infopane.cpp:37 +msgid "Press enter or lose focus to submit" +msgstr "" + +#: src/windows/guildsettings/infopane.cpp:53 +msgid "Click to choose a file, right click to paste" +msgstr "" + +#: src/windows/guildsettings/infopane.cpp:109 +msgid "Failed to set guild name" +msgstr "" + +#: src/windows/guildsettings/infopane.cpp:123 +msgid "Failed to set guild icon" +msgstr "" + +#: src/windows/guildsettings/infopane.cpp:147 +msgid "Choose new guild icon" +msgstr "" + +#: src/windows/guildsettings/infopane.cpp:170 +msgid "Supported images" +msgstr "" + +#: src/windows/guildsettings/infopane.cpp:183 +msgid "All files" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:34 +msgid "Code" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:35 +msgid "Expires" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:36 +msgid "Created by" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:37 +msgid "Uses" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:38 +msgid "Max uses" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:39 +msgid "Grants temporary membership" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:64 +msgid "Never" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:71 +msgid "Unlimited" +msgstr "" + +#: src/windows/guildsettings/invitespane.cpp:106 +msgid "Failed to delete invite" +msgstr "" + +#: src/windows/guildsettings/memberspane.cpp:20 +msgid "Some members may not be shown if the client is not aware of them" +msgstr "" + +#: src/windows/guildsettings/memberspane.cpp:178 +msgid "User is a bot" +msgstr "" + +#: src/windows/guildsettings/memberspane.cpp:213 +msgid "User ID: " +msgstr "" + +#: src/windows/guildsettings/memberspane.cpp:216 +msgid "Joined server: " +msgstr "" + +#: src/windows/guildsettings/memberspane.cpp:218 +msgid "Joined server: Unknown" +msgstr "" + +#: src/windows/guildsettings/memberspane.cpp:219 +msgid "Nickname: " +msgstr "" + +#: src/windows/guildsettings/memberspane.cpp:222 +msgid "Boosting since %1" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:71 +msgid "Failed to set role position" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:217 +msgid "Press enter to submit" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:236 +msgid "Failed to set role color" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:267 +msgid "General" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:277 +msgid "Text Channels" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:295 +msgid "Membership" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:303 +msgid "Advanced" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:305 +msgid "Voice Channels" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:319 +msgid "Events" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:412 +msgid "Failed to set role name" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:23 +msgid "Deafen" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:24 +msgid "Suppress Noise" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:25 +msgid "Mix Mono" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:26 src/windows/voice/voicewindow.cpp:381 +msgid "Request to Speak" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:28 +msgid "You've been invited to speak" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:30 +msgid "Decline" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:33 +msgid "More _Settings" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:97 +msgid "" +"Voice Activation Detection method\n" +"Gate - Simple volume threshold. Slider changes threshold\n" +"RNNoise - Heavier on CPU. Slider changes probability threshold" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:180 +msgid "Threshold" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:190 +msgid "VAD Method" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:191 +msgid "Output Device" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:192 +msgid "Input Device" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:235 +msgid "Speakers" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:238 +msgid "Audience" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:259 +msgid "Input Settings" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:373 +msgid "Leave the Stage" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:375 +msgid "Speak on Stage" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:377 +msgid "Cancel Request" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:379 +msgid "Decline Invite" +msgstr "" + +#: src/windows/voice/voicewindow.cpp:386 +msgid "Topic: " +msgstr "" diff --git a/po/pt_BR.po b/po/pt_BR.po new file mode 100644 index 00000000..2bf385a9 --- /dev/null +++ b/po/pt_BR.po @@ -0,0 +1,2444 @@ +# Portuguese translations for PACKAGE package +# Traduções em português brasileiro para o pacote PACKAGE. +# Copyright (C) 2024 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Gabriel de Moura , 2024. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-27 18:08-0300\n" +"PO-Revision-Date: 2024-06-17 11:45-0300\n" +"Last-Translator: Gabriel de Moura \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: src/abaddon.cpp:216 +#, c++-format +msgid "css failed parsing ({})" +msgstr "CSS falhou em ser lido ({})" + +#: src/abaddon.cpp:232 +msgid "The PNG pixbufloader wasn't detected. Abaddon may not work as a result." +msgstr "" +"A biblioteca pixbufloader para arquivos PNG não foi detectado. Abaddon pode " +"não funcionar como esperado." + +#: src/abaddon.cpp:238 +msgid "" +"The GIF pixbufloader wasn't detected. Animations may not display as a result." +msgstr "" +"A biblioteca pixbufloader para arquivos GIF não foi detectado. Animações " +"podem não funcionar corretamente." + +#: src/abaddon.cpp:253 +msgid "The settings file could not be opened!" +msgstr "Não foi possível carregar o arquivo de configurações!" + +#: src/abaddon.cpp:259 +msgid "The emoji file couldn't be loaded!" +msgstr "Não foi possível carregar o arquivo de emoji!" + +#: src/abaddon.cpp:265 +msgid "The Discord cache could not be created!" +msgstr "Não foi possível criar cache para o Discord!" + +#: src/abaddon.cpp:273 +msgid "The audio engine could not be initialized!" +msgstr "Não foi possível inicializar o motor de áudio!" + +#: src/abaddon.cpp:334 +msgid "Quit" +msgstr "Sair" + +#: src/abaddon.cpp:469 +msgid "Discord rejected your token" +msgstr "O Discord rejeitou o seu token de autenticação" + +#: src/abaddon.cpp:474 +#, c++-format +msgid "Lost connection with Discord's gateway. Try reconnecting (code {})" +msgstr "Conexão com o gateway do Discord perdida. Tente novamente (code {})" + +#: src/abaddon.cpp:484 src/abaddon.cpp:927 +msgid "This thread is archived. Sending a message will unarchive it" +msgstr "Esta thread está arquivada. Mandar uma mensagem vai desarquivá-la" + +#: src/abaddon.cpp:627 +msgid "" +"Cookies could not be fetched. This may increase your chances of being " +"flagged by Discord's anti-spam" +msgstr "" +"Não foi possível obter cookies. Isto pode aumentar as chances de ser pego " +"pelo sistema anti-spam do Discord" + +#: src/abaddon.cpp:636 +msgid "" +"Build number could not be fetched. This may increase your chances of being " +"flagged by Discord's anti-spam" +msgstr "" +"Não foi possível obter o número de build. Isto pode aumentar as chances de " +"ser pego pelo sistema anti-spam do Discord" + +#: src/abaddon.cpp:653 +msgid "Failed to accept the verification gate." +msgstr "Falha ao aceitar a porta de verificação." + +#: src/abaddon.cpp:678 +msgid "Insert Mention" +msgstr "Inserir Menção" + +#: src/abaddon.cpp:679 +msgid "Ban" +msgstr "Banir" + +#: src/abaddon.cpp:680 +msgid "Kick" +msgstr "Expulsar" + +#: src/abaddon.cpp:681 src/components/chatlist.cpp:298 +#: src/windows/guildsettings/banspane.cpp:13 +#: src/windows/guildsettings/emojispane.cpp:18 +msgid "Copy ID" +msgstr "Copiar ID" + +#: src/abaddon.cpp:682 +msgid "Go to DM" +msgstr "Ir para DM" + +#: src/abaddon.cpp:683 src/windows/guildsettingswindow.cpp:66 +msgid "Roles" +msgstr "Cargos" + +#: src/abaddon.cpp:684 +msgid "View Profile" +msgstr "Ver Perfil" + +#: src/abaddon.cpp:685 +msgid "Remove From Group" +msgstr "Remover do Grupo" + +#: src/abaddon.cpp:1003 +#, c++-format +msgid "Are you sure you want to leave {}?" +msgstr "Você tem certeza de que quer sair {}?" + +#: src/abaddon.cpp:1013 +#, c++-format +msgid "Are you sure you want to kick {}?" +msgstr "Você tem certeza de que quer expulsar {}?" + +#: src/abaddon.cpp:1023 +#, c++-format +msgid "Are you sure you want to ban {}?" +msgstr "Você tem certeza de que quer banir {}?" + +#: src/abaddon.cpp:1120 +#, c++-format +msgid "css failed to load ({})" +msgstr "CSS falhou em ser carregado ({})" + +#: src/startup.cpp:14 +msgid "Getting connection info..." +msgstr "Obtendo informações sobre a conexão..." + +#: src/discord/permissions.cpp:16 +msgid "None" +msgstr "Nenhum" + +#: src/discord/permissions.cpp:18 +msgid "Create Invite" +msgstr "Criar Convite" + +#: src/discord/permissions.cpp:20 +msgid "Kick Members" +msgstr "Expulsar Membros" + +#: src/discord/permissions.cpp:22 +msgid "Ban Members" +msgstr "Banir Membros" + +#: src/discord/permissions.cpp:24 +msgid "Administrator" +msgstr "Administrador" + +#: src/discord/permissions.cpp:26 +msgid "Manage Channels" +msgstr "Gerenciar Canais" + +#: src/discord/permissions.cpp:28 +msgid "Manage Server" +msgstr "Gerenciar Servidor" + +#: src/discord/permissions.cpp:30 +msgid "Add Reactions" +msgstr "Adicionar Reações" + +#: src/discord/permissions.cpp:32 +msgid "View Audit Log" +msgstr "Visualizar Registro de Auditoria" + +#: src/discord/permissions.cpp:34 +msgid "Use Priority Speaker" +msgstr "Usar Orador Prioritário" + +#: src/discord/permissions.cpp:36 +msgid "Video" +msgstr "Vídeo" + +#: src/discord/permissions.cpp:38 +msgid "View Channels" +msgstr "Visualizar Canais" + +#: src/discord/permissions.cpp:40 +msgid "Send Messages" +msgstr "Enviar Mensagens" + +#: src/discord/permissions.cpp:42 +msgid "Use TTS" +msgstr "Usar TTS" + +#: src/discord/permissions.cpp:44 +msgid "Manage Messages" +msgstr "Gerenciar Mensagens" + +#: src/discord/permissions.cpp:46 +msgid "Embed Links" +msgstr "Incorporar Links" + +#: src/discord/permissions.cpp:48 +msgid "Attach Files" +msgstr "Anexar Arquivos" + +#: src/discord/permissions.cpp:50 +msgid "Read Message History" +msgstr "Ler Histórico de Mensagens" + +#: src/discord/permissions.cpp:52 +msgid "Mention @everyone" +msgstr "Mencionar @everyone" + +#: src/discord/permissions.cpp:54 +msgid "Use External Emojis" +msgstr "Usar Emojis Externos" + +#: src/discord/permissions.cpp:56 +msgid "View Server Insights" +msgstr "Visualizar Insights do Servidor" + +#: src/discord/permissions.cpp:58 +msgid "Connect to Voice" +msgstr "Conectar ao Voz" + +#: src/discord/permissions.cpp:60 +msgid "Speak in Voice" +msgstr "Falar no Voz" + +#: src/discord/permissions.cpp:62 +msgid "Mute Members" +msgstr "Silenciar Membros" + +#: src/discord/permissions.cpp:64 +msgid "Deafen Members" +msgstr "Ensurdecer Membros" + +#: src/discord/permissions.cpp:66 +msgid "Move Members" +msgstr "Mover Membros" + +#: src/discord/permissions.cpp:68 +msgid "Use Voice Activation" +msgstr "Usar Ativação por Voz" + +#: src/discord/permissions.cpp:70 +msgid "Change Nickname" +msgstr "Mudar Apelido" + +#: src/discord/permissions.cpp:72 +msgid "Manage Nicknames" +msgstr "Gerenciar Apelidos" + +#: src/discord/permissions.cpp:74 +msgid "Manage Roles" +msgstr "Gerenciar Cargos" + +#: src/discord/permissions.cpp:76 +msgid "Manage Webhooks" +msgstr "Gerenciar Webhooks" + +#: src/discord/permissions.cpp:78 +msgid "Manage Expressions" +msgstr "Gerenciar Expressões" + +#: src/discord/permissions.cpp:80 +msgid "Use Application Commands" +msgstr "Usar Comandos de Aplicativos" + +#: src/discord/permissions.cpp:82 +msgid "Manage Events" +msgstr "Gerenciar Eventos" + +#: src/discord/permissions.cpp:84 +msgid "Manage Threads" +msgstr "Gerenciar Tópicos" + +#: src/discord/permissions.cpp:86 +msgid "Create Public Threads" +msgstr "Criar Tópicos Públicos" + +#: src/discord/permissions.cpp:88 +msgid "Create Private Threads" +msgstr "Criar Tópicos Privados" + +#: src/discord/permissions.cpp:90 +msgid "Use External Stickers" +msgstr "Usar Figurinhas Externas" + +#: src/discord/permissions.cpp:92 +msgid "Send Messages In Threads" +msgstr "Enviar Mensagens em Tópicos" + +#: src/discord/permissions.cpp:94 +msgid "Use Activities" +msgstr "Usar Atividades" + +#: src/discord/permissions.cpp:96 +msgid "Timeout Members" +msgstr "Punição Temporária de Membros" + +#: src/discord/permissions.cpp:100 +msgid "Use Soundboard" +msgstr "Usar Mesa de Som" + +#: src/discord/permissions.cpp:102 +msgid "Create Expressions" +msgstr "Criar Expressões" + +#: src/discord/permissions.cpp:104 +msgid "Create Events" +msgstr "Criar Eventos" + +#: src/discord/permissions.cpp:106 +msgid "Use External Sounds" +msgstr "Usar Sons Externos" + +#: src/discord/permissions.cpp:108 +msgid "Send Voice Messages" +msgstr "Enviar Mensagens de Voz" + +#: src/discord/permissions.cpp:112 +msgid "Set Voice Channel Status" +msgstr "Definir Status do Canal de Voz" + +#: src/discord/permissions.cpp:114 +msgid "Unknown Permission" +msgstr "Permissão Desconhecida" + +#: src/discord/permissions.cpp:123 +msgid "Allows members to invite new people to this server." +msgstr "Permite que os membros convidem novas pessoas para este servidor." + +#: src/discord/permissions.cpp:125 +msgid "" +"Allows members to remove other members from this server. Kicked members will " +"be able to rejoin if they have another invite." +msgstr "" +"Permite que os membros removam outros membros deste servidor. Membros " +"expulsos poderão se juntar novamente se tiverem outro convite." + +#: src/discord/permissions.cpp:127 +msgid "Allows members to permanently ban other members from this server." +msgstr "" +"Permite que os membros banam permanentemente outros membros deste servidor." + +#: src/discord/permissions.cpp:129 +msgid "" +"Members with this permission will have every permission and will also bypass " +"all channel specific permissions or restrictions (for example, these members " +"would get access to all private channels). This is a dangerous permission to " +"grant." +msgstr "" +"Membros com esta permissão terão todas as permissões e também ignorarão " +"todas as permissões ou restrições específicas de canal (por exemplo, esses " +"membros terão acesso a todos os canais privados). Esta é uma permissão " +"perigosa de conceder." + +#: src/discord/permissions.cpp:131 +msgid "Allows members to create, edit, or delete channels." +msgstr "Permite que os membros criem, editem ou excluam canais." + +#: src/discord/permissions.cpp:133 +msgid "" +"Allows members to change this server's name, switch regions, and add bots to " +"this server." +msgstr "" +"Permite que os membros mudem o nome deste servidor, alterem regiões e " +"adicionem bots a este servidor." + +#: src/discord/permissions.cpp:135 +msgid "" +"Allows members to add new emoji reactions to a message. If this permission " +"is disabled, members can still react using any existing reactions on a " +"message." +msgstr "" +"Permite que os membros adicionem novas reações de emoji a uma mensagem. Se " +"esta permissão estiver desativada, os membros ainda poderão reagir usando " +"qualquer reação existente em uma mensagem." + +#: src/discord/permissions.cpp:137 +msgid "" +"Allows members to view a record of who made which changes in this server." +msgstr "" +"Permite que os membros vejam um registro de quem fez quais mudanças neste " +"servidor." + +#: src/discord/permissions.cpp:139 +msgid "" +"Allows members to be more easily heard in voice channels. When activated, " +"the volume of others without this permission will be automatically lowered. " +"Priority Speaker is activated by using the Push to Talk (Priority) keybind." +msgstr "" +"Permite que os membros sejam mais facilmente ouvidos em canais de voz. " +"Quando ativado, o volume dos outros sem essa permissão será automaticamente " +"reduzido. O Orador Prioritário é ativado usando a tecla de atalho Push to " +"Talk (Prioridade)." + +#: src/discord/permissions.cpp:141 +msgid "" +"Allows members to share their video, screen share, or stream a game in this " +"server." +msgstr "" +"Permite que os membros compartilhem seu vídeo, compartilhem a tela ou façam " +"streaming de um jogo neste servidor." + +#: src/discord/permissions.cpp:143 +msgid "" +"Allows members to view channels by default (excluding private channels)." +msgstr "" +"Permite que os membros visualizem canais por padrão (excluindo canais " +"privados)." + +#: src/discord/permissions.cpp:145 +msgid "Allows members to send messages in text channels." +msgstr "Permite que os membros enviem mensagens em canais de texto." + +#: src/discord/permissions.cpp:147 +msgid "" +"Allows members to send text-to-speech messages by starting a message with /" +"tts. These messages can be heard by anyone focused on this channel." +msgstr "" +"Permite que os membros enviem mensagens de texto para fala começando uma " +"mensagem com /tts. Essas mensagens podem ser ouvidas por qualquer pessoa " +"focada nesse canal." + +#: src/discord/permissions.cpp:149 +msgid "Allows members to delete messages by other members or pin any message." +msgstr "" +"Permite que os membros excluam mensagens de outros membros ou fixem qualquer " +"mensagem." + +#: src/discord/permissions.cpp:151 +msgid "" +"Allows links that members share to show embedded content in text channels." +msgstr "" +"Permite que os links compartilhados pelos membros mostrem conteúdo " +"incorporado nos canais de texto." + +#: src/discord/permissions.cpp:153 +msgid "Allows members to upload files or media in text channels." +msgstr "Permite que os membros enviem arquivos ou mídia em canais de texto." + +#: src/discord/permissions.cpp:155 +msgid "" +"Allows members to read previous messages sent in channels. If this " +"permission is disabled, members only see messages sent when they are online " +"and focused on that channel." +msgstr "" +"Permite que os membros leiam mensagens anteriores enviadas nos canais. Se " +"esta permissão estiver desativada, os membros só verão as mensagens enviadas " +"quando estiverem online e focados naquele canal." + +#: src/discord/permissions.cpp:157 +msgid "" +"Allows members to use @everyone (everyone in the server) or @here (only " +"online members in that channel). They can also @mention all roles, even if " +"the role's \"Allow anyone to mention this role\" permission is disabled." +msgstr "" +"Permite que os membros usem @everyone (todos no servidor) ou @here (apenas " +"membros online naquele canal). Eles também podem mencionar todas as funções, " +"mesmo que a permissão \"Permitir que qualquer um mencione esta função\" " +"esteja desativada." + +#: src/discord/permissions.cpp:159 +msgid "" +"Allows members to use emoji from other servers, if they're a Discord Nitro " +"member." +msgstr "" +"Permite que os membros usem emojis de outros servidores, se forem membros do " +"Discord Nitro." + +#: src/discord/permissions.cpp:161 +msgid "" +"Allows members to view Server Insights, which shows data on community " +"growth, engagement, and more." +msgstr "" +"Permite que os membros visualizem os Insights do Servidor, que mostram dados " +"sobre o crescimento da comunidade, engajamento e mais." + +#: src/discord/permissions.cpp:163 +msgid "Allows members to join voice channels and hear others." +msgstr "Permite que os membros entrem em canais de voz e ouçam os outros." + +#: src/discord/permissions.cpp:165 +msgid "" +"Allows members to talk in voice channels. If this permission is disabled, " +"members are default muted until somebody with the \"Mute Members\" " +"permission unmutes them." +msgstr "" +"Permite que os membros falem em canais de voz. Se esta permissão estiver " +"desativada, os membros serão silenciados por padrão até que alguém com a " +"permissão de \"Silenciar Membros\" os ative." + +#: src/discord/permissions.cpp:167 +msgid "Allows members to mute other members in voice channels for everyone." +msgstr "" +"Permite que os membros silenciem outros membros em canais de voz para todos." + +#: src/discord/permissions.cpp:169 +msgid "" +"Allows members to deafen other members in voice channels, which means they " +"won't be able to speak or hear others." +msgstr "" +"Permite que os membros ensurdecam outros membros em canais de voz, o que " +"significa que eles não poderão falar ou ouvir os outros." + +#: src/discord/permissions.cpp:171 +msgid "" +"Allows members to move other members between voice channels that the member " +"with the permission has access to." +msgstr "" +"Permite que os membros movam outros membros entre canais de voz aos quais o " +"membro com a permissão tem acesso." + +#: src/discord/permissions.cpp:173 +msgid "" +"Allows members to speak in voice channels by simply talking. If this " +"permission is disabled, members are required to use Push-to-talk. Good for " +"controlling background noise or noisy members." +msgstr "" +"Permite que os membros falem em canais de voz simplesmente falando. Se esta " +"permissão estiver desativada, os membros precisam usar o Push-to-talk. Bom " +"para controlar o ruído de fundo ou membros barulhentos." + +#: src/discord/permissions.cpp:175 +msgid "" +"Allows members to change their own nickname, a custom name for just this " +"server." +msgstr "" +"Permite que os membros mudem seus próprios apelidos, um nome personalizado " +"apenas para este servidor." + +#: src/discord/permissions.cpp:177 +msgid "Allows members to change the nicknames of other members." +msgstr "Permite que os membros mudem os apelidos de outros membros." + +#: src/discord/permissions.cpp:179 +msgid "" +"Allows members to create new roles and edit or delete roles lower than their " +"highest role. Also allows members to change permissions of individual " +"channels that they have access to." +msgstr "" +"Permite que os membros criem novas funções e editem ou excluam funções " +"abaixo de sua função mais alta. Também permite que os membros alterem " +"permissões de canais individuais que eles têm acesso." + +#: src/discord/permissions.cpp:181 +msgid "" +"Allows members to create, edit, or delete webhooks, which can post messages " +"from other apps or sites into this server." +msgstr "" +"Permite que os membros criem, editem ou excluam webhooks, que podem postar " +"mensagens de outros aplicativos ou sites neste servidor." + +#: src/discord/permissions.cpp:183 +msgid "" +"Allows members to add or remove custom emoji, stickers, and sounds in this " +"server." +msgstr "" +"Permite que os membros adicionem ou removam emojis, figurinhas e sons " +"personalizados neste servidor." + +#: src/discord/permissions.cpp:185 +msgid "" +"Allows members to use commands from applications, including slash commands " +"and context menu commands." +msgstr "" +"Permite que os membros usem comandos de aplicativos, incluindo comandos de " +"barra e comandos do menu de contexto." + +#: src/discord/permissions.cpp:187 +msgid "Allows members to edit and cancel events." +msgstr "Permite que os membros editem e cancelem eventos." + +#: src/discord/permissions.cpp:189 +msgid "" +"Allows members to rename, delete, close, and turn on slow mode for threads. " +"They can also view private threads." +msgstr "" +"Permite que os membros renomeiem, excluam, fechem e ativem o modo lento para " +"tópicos. Também permite que vejam tópicos privados." + +#: src/discord/permissions.cpp:191 +msgid "Allows members to create threads that everyone in a channel can view." +msgstr "" +"Permite que os membros criem tópicos que todos em um canal possam visualizar." + +#: src/discord/permissions.cpp:193 +msgid "Allows members to create invite-only threads." +msgstr "Permite que os membros criem tópicos apenas por convite." + +#: src/discord/permissions.cpp:195 +msgid "" +"Allows members to use stickers from other servers, if they're a Discord " +"Nitro member." +msgstr "" +"Permite que os membros usem figurinhas de outros servidores, se forem " +"membros do Discord Nitro." + +#: src/discord/permissions.cpp:197 +msgid "Allows members to send messages in threads." +msgstr "Permite que os membros enviem mensagens em tópicos." + +#: src/discord/permissions.cpp:199 +msgid "Allows members to use Activities in this server." +msgstr "Permite que os membros usem Atividades neste servidor." + +#: src/discord/permissions.cpp:201 +msgid "" +"When you put a user in timeout they will not be able to send messages in " +"chat, reply within threads, react to messages, or speak in voice or Stage " +"channels." +msgstr "" +"Quando você coloca um usuário em timeout, ele não poderá enviar mensagens no " +"chat, responder em tópicos, reagir a mensagens ou falar em canais de voz ou " +"Stage." + +#: src/discord/permissions.cpp:205 +msgid "Allows members to send sounds from server soundboard." +msgstr "Permite que os membros enviem sons da mesa de som do servidor." + +#: src/discord/permissions.cpp:207 +msgid "" +"Allows members to add custom emoji, stickers, and sounds in this server." +msgstr "" +"Permite que os membros adicionem emojis, figurinhas e sons personalizados " +"neste servidor." + +#: src/discord/permissions.cpp:209 +msgid "Allows members to create events." +msgstr "Permite que os membros criem eventos." + +#: src/discord/permissions.cpp:211 +msgid "" +"Allows members to use sounds from other servers, if they're a Discord Nitro " +"member." +msgstr "" +"Permite que os membros usem sons de outros servidores, se forem membros do " +"Discord Nitro." + +#: src/discord/permissions.cpp:213 +msgid "Allows members to send voice messages." +msgstr "Permite que os membros enviem mensagens de voz." + +#: src/discord/permissions.cpp:217 +msgid "Allows members to create and edit voice channel status." +msgstr "Permite que os membros criem e editem o status do canal de voz." + +#: src/dialogs/confirm.cpp:6 +msgid "Confirm" +msgstr "Confirmar" + +#: src/dialogs/confirm.cpp:9 src/dialogs/friendpicker.cpp:15 +#: src/dialogs/setstatus.cpp:27 src/dialogs/textinput.cpp:12 +#: src/dialogs/token.cpp:16 src/components/friendslist.cpp:293 +msgid "Cancel" +msgstr "Cancelar" + +#: src/dialogs/confirm.cpp:15 +msgid "Are you sure?" +msgstr "Você tem certeza?" + +#: src/dialogs/friendpicker.cpp:8 +msgid "Pick a friend" +msgstr "Selecione um Amigo" + +#: src/dialogs/setstatus.cpp:24 src/windows/mainwindow.cpp:268 +msgid "Set Status" +msgstr "Definir Status" + +#: src/dialogs/setstatus.cpp:35 src/dialogs/setstatus.cpp:39 +#: src/components/friendslist.cpp:27 +msgid "Online" +msgstr "Online" + +#: src/dialogs/setstatus.cpp:36 +msgid "Do Not Disturb" +msgstr "Não Perturbe" + +#: src/dialogs/setstatus.cpp:37 +msgid "Away" +msgstr "Ocupado" + +#: src/dialogs/setstatus.cpp:38 +msgid "Invisible" +msgstr "Invisível" + +#: src/dialogs/setstatus.cpp:41 +msgid "Playing" +msgstr "Jogando" + +#: src/dialogs/setstatus.cpp:42 +msgid "Streaming" +msgstr "Transmitindo" + +#: src/dialogs/setstatus.cpp:43 +msgid "Listening to" +msgstr "Escutando" + +#: src/dialogs/setstatus.cpp:44 +msgid "Watching" +msgstr "Assitindo" + +#: src/dialogs/setstatus.cpp:45 src/dialogs/setstatus.cpp:47 +msgid "Custom" +msgstr "Customizado" + +#: src/dialogs/setstatus.cpp:46 +msgid "Competing in" +msgstr "Competindo em" + +#: src/dialogs/setstatus.cpp:57 +#, c++-format +msgid "How are you, {}?" +msgstr "Como você está, {}?" + +#: src/dialogs/setstatus.cpp:59 +msgid "Status" +msgstr "Status" + +#: src/dialogs/setstatus.cpp:61 +msgid "Activity" +msgstr "Atividade" + +#: src/dialogs/token.cpp:13 src/windows/mainwindow.cpp:262 +msgid "Set Token" +msgstr "Definir Token" + +#: src/dialogs/verificationgate.cpp:8 +msgid "Verification Required" +msgstr "Verificação Necessária" + +#: src/dialogs/verificationgate.cpp:14 src/components/friendslist.cpp:258 +#: src/windows/voice/voicewindow.cpp:29 +msgid "Accept" +msgstr "Aceitar" + +#: src/components/chatinput.cpp:143 +msgid "Choose file" +msgstr "Escolha um arquivo" + +#: src/components/chatinput.cpp:389 src/components/friendslist.cpp:287 +msgid "Remove" +msgstr "Remover" + +#: src/components/chatinput.cpp:394 +msgid "Change Filename" +msgstr "Alterar Nome do Arquivo" + +#: src/components/chatinput.cpp:396 +msgid "Enter new filename for attachment" +msgstr "Insira novo nome de arquivo para anexo" + +#: src/components/chatinput.cpp:396 +msgid "Enter filename" +msgstr "Inserir nome de arquivo" + +#: src/components/chatinput.cpp:404 +msgid "Change Alt-Text" +msgstr "Alterar texto alternativo" + +#: src/components/chatinput.cpp:406 +msgid "Enter description (alt-text) for attachment" +msgstr "Inserir descrição para o anexo" + +#: src/components/chatinput.cpp:406 +msgid "Enter alt-text" +msgstr "Inserir texto alternativo" + +#: src/components/chatinputindicator.cpp:119 +#, c++-format +msgid "{} is typing..." +msgstr "{} está digitando..." + +#: src/components/chatinputindicator.cpp:121 +#, c++-format +msgid "{} and {} are typing" +msgstr "{} e {} estão digitando" + +#: src/components/chatinputindicator.cpp:125 +#, c++-format +msgid "{}, {}, {} and {} are typing..." +msgstr "{}, {}, {} e {} estão digitando" + +#: src/components/chatinputindicator.cpp:132 +msgid "Several people are typing..." +msgstr "Várias pessoas estão digitando..." + +#: src/components/chatlist.cpp:305 +msgid "Delete Message" +msgstr "Deletar Mensagem" + +#: src/components/chatlist.cpp:312 +msgid "Edit Message" +msgstr "Editar Mensagem" + +#: src/components/chatlist.cpp:319 +msgid "Copy Content" +msgstr "Copiar Conteúdo" + +#: src/components/chatlist.cpp:328 +msgid "Reply To" +msgstr "Responder a" + +#: src/components/chatlist.cpp:335 +msgid "Unpin" +msgstr "Desafixar" + +#: src/components/chatlist.cpp:341 +msgid "Pin" +msgstr "Fixar" + +#: src/components/chatmessage.cpp:16 +msgid "Copy Link" +msgstr "Copiar Link" + +#: src/components/chatmessage.cpp:147 +msgid "deleted" +msgstr "deletado" + +#: src/components/chatmessage.cpp:149 +msgid "edited" +msgstr "editado" + +#: src/components/chatmessage.cpp:203 +msgid "boosted server" +msgstr "impulsionou servidor" + +#: src/components/chatmessage.cpp:206 +msgid "user joined" +msgstr "usuário entrou" + +#: src/components/chatmessage.cpp:209 +msgid "message pinned" +msgstr "mensagem fixada" + +#: src/components/chatmessage.cpp:219 +#, c++-format +msgid "used {} with {}" +msgstr "usou {} com {}" + +#: src/components/chatmessage.cpp:234 +#, c++-format +msgid "" +"{} added {}" +msgstr "" +"{} adicionou {}" + +#: src/components/chatmessage.cpp:244 +#, c++-format +msgid "" +"{} left" +msgstr "" +"{} saiu" + +#: src/components/chatmessage.cpp:246 +#, c++-format +msgid "" +"{} removed {}" +msgstr "" +"{} removeu {}" + +#: src/components/chatmessage.cpp:253 +#, c++-format +msgid "{} changed the name to {}" +msgstr "{} alterou o nome para {}" + +#: src/components/chatmessage.cpp:258 +#, c++-format +msgid "{} changed the channel icon" +msgstr "{} alterou o ícone do canal" + +#: src/components/chatmessage.cpp:266 +#, c++-format +msgid "" +"{} just boosted the server {} times! {} has " +"achieved Level {}!" +msgstr "" +"{} acabou de impulsionar o servidor {} " +"vezes! {} atingiu Nível {}!" + +#: src/components/chatmessage.cpp:276 +#, c++-format +msgid "" +"{} has added {} to this channel. Its most " +"important updates will show up here." +msgstr "" +"{} adicionou {} para este canalSuas " +"atualizações mais importantes vão aparecer aqui." + +#: src/components/chatmessage.cpp:282 +msgid "started a call" +msgstr "iniciou uma chamada" + +#: src/components/chatmessage.cpp:285 +msgid "" +"This server has been removed from Server Discovery because it no longer " +"passes all the requirements." +msgstr "" +"Este servidor foi removido \"Server Discovery\" porque ele nãoatende mais a " +"todos os requisitos" + +#: src/components/chatmessage.cpp:288 +msgid "" +"This server is eligible for Server Discovery again and has been " +"automatically relisted!" +msgstr "" +"Este servidor é elegível para o \"Server Discovery\" novamente e foi " +"automaticamente recadastrado" + +#: src/components/chatmessage.cpp:291 +msgid "" +"This server has failed Discovery activity requirements for 1 week. If this " +"server fails for 4 weeks in a row, it will be automatically removed from " +"Discovery." +msgstr "" +"Este servidor falhou em cumprir os requisitos do \"Discovery\" por 1 semana. " +"Se o servidor falhar por 4 semanas consecutivas, ele será automaticamente " +"removido do \"Server Discovery\"" + +#: src/components/chatmessage.cpp:294 +msgid "" +"This server has failed Discovery activity requirements for 3 weeks in a row. " +"If this server fails for 1 more week, it will be removed from Discovery." +msgstr "" +"Este servidor falhou em cumprir os requisitos do \"Discovery\" por 3 semanas " +"consecutivas. Se o servidor falhar por mais 1 semana, ele será " +"automaticamente removido do \"Server Discovery\"" + +#: src/components/chatmessage.cpp:300 +#, c++-format +msgid "{} started a thread: " +msgstr "{} iniciou uma thread: " + +#: src/components/chatmessage.cpp:307 +#, c++-format +msgid "{} started a thread: {}" +msgstr "{} iniciou uma thread: {}" + +#: src/components/chatmessage.cpp:714 src/components/chatmessage.cpp:737 +#: src/windows/guildsettings/auditlogpane.cpp:44 +msgid "Unknown User" +msgstr "Usuário Desconhecido" + +#: src/components/chatmessage.cpp:730 +#, c++-format +msgid "{} used /{}" +msgstr "{} usou /{}" + +#: src/components/chatmessage.cpp:741 +msgid "deleted message" +msgstr "mensagem apagada" + +#: src/components/chatmessage.cpp:747 +msgid "attachment" +msgstr "anexo" + +#: src/components/chatmessage.cpp:749 +msgid "embed" +msgstr "embutido" + +#: src/components/chatmessage.cpp:769 +msgid "reply unavailable" +msgstr "resposta indisponível" + +#: src/components/chatwindow.cpp:334 +#, c++-format +msgid "Replying to {}" +msgstr "Respondendo {}" + +#: src/components/chatwindow.cpp:336 +msgid "Replying..." +msgstr "Respondendo..." + +#: src/components/chatwindow.cpp:356 +msgid "Editing..." +msgstr "Editando..." + +#: src/components/friendslist.cpp:26 src/windows/mainwindow.cpp:290 +msgid "Friends" +msgstr "Amigos" + +#: src/components/friendslist.cpp:28 +msgid "Pending" +msgstr "Pendente" + +#: src/components/friendslist.cpp:29 +msgid "Blocked" +msgstr "Bloqueado" + +#: src/components/friendslist.cpp:114 +msgid "Failed to accept" +msgstr "Falhou em aceitar" + +#: src/components/friendslist.cpp:129 +#, c++-format +msgid "Are you sure you want to unblock {}?" +msgstr "Você tem certeza de que quer desbloquear {}?" + +#: src/components/friendslist.cpp:132 +#, c++-format +msgid "Are you sure you want to remove {}?" +msgstr "Você tem certeza de que quer remover {}?" + +#: src/components/friendslist.cpp:135 +#, c++-format +msgid "Are you sure you want to ignore {}?" +msgstr "Você tem certeza de que quer ignorar {}?" + +#: src/components/friendslist.cpp:138 +#, c++-format +msgid "Are you sure you want to cancel your request to {}?" +msgstr "Você tem certeza de que quer cancelar pedido de amizade para {}?" + +#: src/components/friendslist.cpp:146 +msgid "Failed to remove user" +msgstr "Falhou em remover usuário" + +#: src/components/friendslist.cpp:195 +msgid "Add a Friend" +msgstr "Adicionar um amigo" + +#: src/components/friendslist.cpp:197 +msgid "Add" +msgstr "Adicionar" + +#: src/components/friendslist.cpp:207 +msgid "Enter a Username#1234" +msgstr "Insira um NomeDeUsuário#1234" + +#: src/components/friendslist.cpp:220 +msgid "Invalid input" +msgstr "Entrada inválida" + +#: src/components/friendslist.cpp:230 +msgid "Hang on..." +msgstr "Um momento..." + +#: src/components/friendslist.cpp:235 +msgid "Success!" +msgstr "Sucesso!" + +#: src/components/friendslist.cpp:237 +#, c++-format +msgid "Failed: {}" +msgstr "Falhou: {}" + +#: src/components/friendslist.cpp:290 +msgid "Ignore" +msgstr "Ignorar" + +#: src/components/friendslist.cpp:331 +msgid "Incoming Friend Request" +msgstr "Pedido de Amizade Pendente" + +#: src/components/friendslist.cpp:334 +msgid "Outgoing Friend Request" +msgstr "Pedido de Amizade Enviado" + +#: src/components/ratelimitindicator.cpp:88 +msgid "You may bypass slowmode." +msgstr "Você é imune ao modo lento" + +#: src/components/ratelimitindicator.cpp:93 +#, c++-format +msgid "{}s" +msgstr "{}s" + +#: src/components/ratelimitindicator.cpp:96 +#, c++-format +msgid "Slowmode is enabled. Members can send one message every {} seconds" +msgstr "" +"Modo lento está ativo. Membros podem enviar apenas uma mensagem a cada {} " +"segundos" + +#: src/components/voiceinfobox.cpp:33 src/components/voiceinfobox.cpp:34 +msgid "You shouldn't see me" +msgstr "Você não deveria me ver" + +#: src/components/voiceinfobox.cpp:49 +msgid "Connecting" +msgstr "Conectando" + +#: src/components/voiceinfobox.cpp:52 +msgid "Establishing connection" +msgstr "Estabelecendo conexão" + +#: src/components/voiceinfobox.cpp:55 +msgid "Connected" +msgstr "Conectado" + +#: src/components/voiceinfobox.cpp:59 +msgid "Disconnected" +msgstr "Desconectado" + +#: src/components/voiceinfobox.cpp:62 src/components/voiceinfobox.cpp:118 +msgid "Unknown" +msgstr "Desconhecido" + +#: src/components/channellist/channellisttree.cpp:19 +#: src/components/channellist/channellisttree.cpp:23 +#: src/components/channellist/channellisttree.cpp:24 +#: src/components/channellist/channellisttree.cpp:37 +#: src/components/channellist/channellisttree.cpp:44 +msgid "_Copy ID" +msgstr "_Copiar ID" + +#: src/components/channellist/channellisttree.cpp:20 +msgid "View _Settings" +msgstr "Ver _Configurações" + +#: src/components/channellist/channellisttree.cpp:21 +#: src/components/channellist/channellisttree.cpp:45 +msgid "_Leave" +msgstr "_Sair" + +#: src/components/channellist/channellisttree.cpp:22 +#: src/components/channellist/channellisttree.cpp:25 +#: src/components/channellist/channellisttree.cpp:35 +#: src/components/channellist/channellisttree.cpp:48 +msgid "Mark as _Read" +msgstr "Marcar como _Lido" + +#: src/components/channellist/channellisttree.cpp:27 +#: src/components/channellist/channellisttree.cpp:28 +msgid "Open in New _Tab" +msgstr "Abrir em Nova _Aba" + +#: src/components/channellist/channellisttree.cpp:31 +#: src/components/channellist/channellisttree.cpp:33 +msgid "_Join" +msgstr "_Entrar" + +#: src/components/channellist/channellisttree.cpp:32 +#: src/components/channellist/channellisttree.cpp:34 +msgid "_Disconnect" +msgstr "_Desconectar" + +#: src/components/channellist/channellisttree.cpp:36 +msgid "Open _Chat" +msgstr "Abrir _Chat" + +#: src/components/channellist/channellisttree.cpp:41 +msgid "Join _Voice" +msgstr "Entrar em _Voz" + +#: src/components/channellist/channellisttree.cpp:42 +msgid "_Disconnect Voice" +msgstr "_Desconectar da Voz" + +#: src/components/channellist/channellisttree.cpp:46 +msgid "_Archive" +msgstr "_Arquivar" + +#: src/components/channellist/channellisttree.cpp:47 +msgid "_Unarchive" +msgstr "_Desarquivar" + +#: src/components/channellist/channellisttree.cpp:259 +msgid "Are you sure you want to leave this group DM?" +msgstr "Você tem certeza de que quer sair deste grupo de DM?" + +#: src/components/channellist/channellisttree.cpp:297 +msgid "Are you sure you want to leave this thread?" +msgstr "Você tem certeza de que quer sair desta thread?" + +#: src/components/channellist/channellisttree.cpp:1199 +msgid "Direct Messages" +msgstr "Mensagems Diretas" + +#: src/components/channellist/channellisttree.cpp:1371 +msgid "Close" +msgstr "Fechar" + +#: src/components/channellist/channellisttree.cpp:1371 +msgid "Leave" +msgstr "Sair" + +#: src/components/channellist/channellisttree.cpp:1425 +#: src/components/channellist/channellisttree.cpp:1439 +#: src/components/channellist/channellisttree.cpp:1503 +#: src/components/channellist/channellisttree.cpp:1528 +msgid "Unmute" +msgstr "Desmutar" + +#: src/components/channellist/channellisttree.cpp:1427 +#: src/components/channellist/channellisttree.cpp:1441 +#: src/components/channellist/channellisttree.cpp:1505 +#: src/components/channellist/channellisttree.cpp:1530 +#: src/windows/voice/voicewindow.cpp:22 +msgid "Mute" +msgstr "Mutar" + +#: src/windows/guildsettingswindow.cpp:64 +msgid "Info" +msgstr "Informações" + +#: src/windows/guildsettingswindow.cpp:65 src/windows/mainwindow.cpp:298 +msgid "Members" +msgstr "Membros" + +#: src/windows/guildsettingswindow.cpp:67 +msgid "Bans" +msgstr "Banimentos" + +#: src/windows/guildsettingswindow.cpp:69 +msgid "Invites" +msgstr "Convites" + +#: src/windows/guildsettingswindow.cpp:70 +msgid "Emojis" +msgstr "Emojis" + +#: src/windows/guildsettingswindow.cpp:72 +msgid "Audit Log" +msgstr "Registros de Auditoria" + +#: src/windows/mainwindow.cpp:258 +msgid "Connect" +msgstr "Conectar" + +#: src/windows/mainwindow.cpp:260 src/windows/voice/voicewindow.cpp:27 +msgid "Disconnect" +msgstr "Desconectar" + +#: src/windows/mainwindow.cpp:263 +msgid "Login with QR Code" +msgstr "Fazer Log-in com código QR" + +#: src/windows/mainwindow.cpp:266 +msgid "Not compiled with support" +msgstr "Não suportado pela build atual" + +#: src/windows/mainwindow.cpp:270 +msgid "Add user to DM" +msgstr "Adicionar usuário a DM" + +#: src/windows/mainwindow.cpp:279 +msgid "File" +msgstr "Arquivo" + +#: src/windows/mainwindow.cpp:281 +msgid "Reload CSS" +msgstr "Recarregar CSS" + +#: src/windows/mainwindow.cpp:282 +msgid "Clear file cache" +msgstr "Limpar cache de arquivo" + +#: src/windows/mainwindow.cpp:283 +msgid "Dump ready message" +msgstr "Descarregar mensagem de pronto" + +#: src/windows/mainwindow.cpp:288 src/windows/voice/voicewindow.cpp:32 +msgid "View" +msgstr "Ver" + +#: src/windows/mainwindow.cpp:291 +msgid "Pins" +msgstr "Pinos" + +#: src/windows/mainwindow.cpp:292 +msgid "Threads" +msgstr "Threads" + +#: src/windows/mainwindow.cpp:293 +msgid "Mark Server as Read" +msgstr "Marcar Servidor como Lido" + +#: src/windows/mainwindow.cpp:295 +msgid "Channels" +msgstr "Canais" + +#: src/windows/mainwindow.cpp:302 +msgid "Go Back" +msgstr "Voltar" + +#: src/windows/mainwindow.cpp:303 +msgid "Go Forward" +msgstr "Avançar" + +#: src/windows/pinnedwindow.cpp:15 +msgid "#%1 - Pinned Messages" +msgstr "" + +#: src/windows/pinnedwindow.cpp:17 +msgid "Pinned Messages" +msgstr "Mensagens Fixadas" + +#: src/windows/profilewindow.cpp:80 +msgid "User Info" +msgstr "Informações do Usuário" + +#: src/windows/profilewindow.cpp:81 +msgid "Mutual Servers" +msgstr "Servidores Mútuos" + +#: src/windows/profilewindow.cpp:82 +msgid "Mutual Friends" +msgstr "Amigos Mútuos" + +#: src/windows/profilewindow.cpp:113 +msgid "Originally known as %1" +msgstr "" + +#: src/windows/threadswindow.cpp:9 +msgid "Public" +msgstr "Público" + +#: src/windows/threadswindow.cpp:10 +msgid "Private" +msgstr "Privado" + +#: src/windows/threadswindow.cpp:16 +msgid "#%1 - Threads" +msgstr "" + +#: src/windows/threadswindow.cpp:32 +msgid "Active Threads" +msgstr "Threads Ativas" + +#: src/windows/threadswindow.cpp:33 +msgid "Archived Threads" +msgstr "Threads Arquivadas" + +#: src/windows/voicesettingswindow.cpp:21 +#: src/windows/voicesettingswindow.cpp:53 +msgid "Voice" +msgstr "Voz" + +#: src/windows/voicesettingswindow.cpp:22 +#: src/windows/voicesettingswindow.cpp:54 +msgid "Music" +msgstr "Música" + +#: src/windows/voicesettingswindow.cpp:23 +msgid "Restricted" +msgstr "Restrito" + +#: src/windows/voicesettingswindow.cpp:25 +msgid "" +"Sets the coding mode for the Opus encoder\n" +"Voice - Optimize for voice quality\n" +"Music - Optimize for non-voice signals incl. music\n" +"Restricted - Optimize for non-voice, low latency. Not recommended" +msgstr "" +"Define o modo de codificação para codificador Opus\n" +"Voz - Otimizar para qualidade de voz\n" +"Música - Optimize for non-voice signals incl. music\n" +"Restrito - Optimize for non-voice, low latency. Not recommended" + +#: src/windows/voicesettingswindow.cpp:52 +msgid "Auto" +msgstr "Automático" + +#: src/windows/voicesettingswindow.cpp:56 +msgid "" +"Signal hint. Tells Opus what the current signal is\n" +"Auto - Let Opus figure it out\n" +"Voice - Tell Opus it's a voice signal\n" +"Music - Tell Opus it's a music signal" +msgstr "" +"Tipo de sinal. Informa Opus sobre o tipo de sinal\n" +"Automático - Opus descobre automaticamente\n" +"Voz - Indica a Opus que é um sinal de voz\n" +"Música - Indica a Opus que é um sinal de música" + +#: src/windows/voicesettingswindow.cpp:130 +msgid "Coding Mode" +msgstr "Modo de Codificação" + +#: src/windows/voicesettingswindow.cpp:131 +msgid "Signal Hint" +msgstr "Tipo de Sinal" + +#: src/windows/voicesettingswindow.cpp:132 +msgid "Bitrate" +msgstr "Taxa de bits" + +#: src/windows/voicesettingswindow.cpp:133 +#: src/windows/voice/voicewindow.cpp:181 +msgid "Gain" +msgstr "Ganho" + +#: src/windows/profile/mutualguildspane.cpp:38 +msgid "Unknown Server" +msgstr "Servidor Desconhecido" + +#: src/windows/profile/userinfopane.cpp:144 +msgid "NOTE" +msgstr "ANOTAÇÃO" + +#: src/windows/profile/userinfopane.cpp:190 +msgid "ABOUT ME" +msgstr "SOBRE MIM" + +#: src/windows/profile/userinfopane.cpp:216 +msgid "Failed to set note" +msgstr "Falhou em definir anotação" + +#: src/windows/profile/userinfopane.cpp:238 +#: src/windows/guildsettings/memberspane.cpp:214 +msgid "Account created: " +msgstr "Conta criada: " + +#: src/windows/guildsettings/auditlogpane.cpp:55 +msgid "%1 made changes to %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:61 +msgid "Set the server icon" +msgstr "Definiu o ícone do servidor" + +#: src/windows/guildsettings/auditlogpane.cpp:66 +msgid "Set the server name to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:69 +msgid "Set the server name" +msgstr "Definiu o nome do servidor" + +#: src/windows/guildsettings/auditlogpane.cpp:76 +msgid "%1 created a voice channel #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:79 +msgid "%1 created a text channel #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:87 +#: src/windows/guildsettings/auditlogpane.cpp:477 +msgid "Set the name to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:91 +#: src/windows/guildsettings/auditlogpane.cpp:128 +msgid "Marked the channel as NSFW" +msgstr "Marcou o canal como NSFW" + +#: src/windows/guildsettings/auditlogpane.cpp:93 +#: src/windows/guildsettings/auditlogpane.cpp:130 +msgid "Unmarked the channel as NSFW" +msgstr "Desmarcou o canal como NSFW" + +#: src/windows/guildsettings/auditlogpane.cpp:100 +msgid "%1 made changes to #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:103 +msgid "%1 made changes to <#%2>" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:113 +#: src/windows/guildsettings/auditlogpane.cpp:384 +#: src/windows/guildsettings/auditlogpane.cpp:503 +msgid "Changed the name from %1 to %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:117 +#: src/windows/guildsettings/auditlogpane.cpp:254 +#: src/windows/guildsettings/auditlogpane.cpp:346 +msgid "Changed the name to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:122 +msgid "Changed the topic to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:124 +msgid "Cleared the topic" +msgstr "Limpou o tópico" + +#: src/windows/guildsettings/auditlogpane.cpp:135 +#: src/windows/guildsettings/auditlogpane.cpp:486 +#: src/windows/guildsettings/auditlogpane.cpp:511 +msgid "Disabled slowmode" +msgstr "Desativou modo câmera lenta" + +#: src/windows/guildsettings/auditlogpane.cpp:137 +#: src/windows/guildsettings/auditlogpane.cpp:488 +#: src/windows/guildsettings/auditlogpane.cpp:513 +msgid "Set slowmode to %1 seconds" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:143 +msgid "%1 removed #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:149 +msgid "%1 created channel overrides for #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:151 +msgid "%1 created channel overrides for <#%2>" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:158 +msgid "%1 updated channel overrides for #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:160 +msgid "%1 updated channel overrides for <#%2>" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:167 +msgid "%1 removed channel overrides for #%2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:169 +msgid "%1 removed channel overrides for <#%2>" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:174 +msgid "%1 kicked %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:177 +msgid "%1 pruned %2 members" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:178 +msgid "For %1 days of inactivity" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:182 +msgid "%1 banned %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:186 +msgid "%1 removed the ban for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:190 +msgid "%1 updated %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:195 +msgid "Deafened them" +msgstr "Desligou o áudio deles" + +#: src/windows/guildsettings/auditlogpane.cpp:195 +msgid "Undeafened them" +msgstr "Ativou o áudio deles" + +#: src/windows/guildsettings/auditlogpane.cpp:197 +msgid "Muted them" +msgstr "Mutou eles" + +#: src/windows/guildsettings/auditlogpane.cpp:197 +msgid "Unmuted them" +msgstr "Desmutou eles" + +#: src/windows/guildsettings/auditlogpane.cpp:199 +msgid "Set their nickname to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:205 +msgid "%1 updated roles for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:210 +msgid "Removed a role %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:212 +msgid "Added a role %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:222 +msgid "%1 moved a user to %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:225 +msgid "%1 moved %2 users to %3" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:231 +msgid "%1 disconnected %2 users from voice" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:237 +msgid "%1 added %2 to the server" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:242 +msgid "%1 created the role %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:247 +msgid "%1 updated the role %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:258 +msgid "Removed the color" +msgstr "Removeu a cor" + +#: src/windows/guildsettings/auditlogpane.cpp:260 +msgid "Set the color to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:263 +msgid "Updated the permissions" +msgstr "Atualizou as permissões" + +#: src/windows/guildsettings/auditlogpane.cpp:265 +msgid "Mentionable" +msgstr "Mencionável" + +#: src/windows/guildsettings/auditlogpane.cpp:265 +msgid "Not mentionable" +msgstr "Não mencionável" + +#: src/windows/guildsettings/auditlogpane.cpp:267 +msgid "Not hoisted" +msgstr "Não içado" + +#: src/windows/guildsettings/auditlogpane.cpp:267 +msgid "Hoisted" +msgstr "Içado" + +#: src/windows/guildsettings/auditlogpane.cpp:275 +msgid "%1 deleted the role %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:280 +msgid "%1 created an invite %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:286 +msgid "For channel %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:291 +msgid "Which has unlimited uses" +msgstr "O qual possui usos ilimitados" + +#: src/windows/guildsettings/auditlogpane.cpp:293 +msgid "Which has %1 uses" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:297 +msgid "With temporary on" +msgstr "Com modo temporário ligado" + +#: src/windows/guildsettings/auditlogpane.cpp:299 +msgid "With temporary off" +msgstr "Com modo temporário desligado" + +#: src/windows/guildsettings/auditlogpane.cpp:307 +msgid "%1 deleted an invite %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:312 +msgid "%1 created the webhook %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:320 +msgid "With channel #%1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:335 +msgid "%1 updated the webhook %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:340 +msgid "%1 updated a webhook" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:349 +msgid "Changed the avatar" +msgstr "Mudou o avatar" + +#: src/windows/guildsettings/auditlogpane.cpp:354 +msgid "Changed the channel to #%1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:357 +msgid "Changed the channel" +msgstr "Mudou o canal" + +#: src/windows/guildsettings/auditlogpane.cpp:366 +msgid "%1 deleted the webhook %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:373 +msgid "%1 created the emoji %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:380 +msgid "%1 updated the emoji %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:391 +msgid "%1 deleted the emoji %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:402 +msgid "%1 deleted %2 messages in #%3" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:406 +msgid "%1 deleted %2 messages" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:414 +msgid "%1 pinned a message by %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:420 +msgid "%1 unpinned a message by %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:425 +msgid "%1 started the stage for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:433 +#: src/windows/guildsettings/auditlogpane.cpp:453 +msgid "Set the topic to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:438 +#: src/windows/guildsettings/auditlogpane.cpp:458 +msgid "Set the privacy level to %1" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:445 +msgid "%1 updated the stage for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:465 +msgid "%1 ended the stage for %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:471 +msgid "%1 created a thread %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:480 +#: src/windows/guildsettings/auditlogpane.cpp:517 +msgid "Archived the thread" +msgstr "Arquivou a thread" + +#: src/windows/guildsettings/auditlogpane.cpp:480 +#: src/windows/guildsettings/auditlogpane.cpp:517 +msgid "Unarchived the thread" +msgstr "Desarquivou a thread" + +#: src/windows/guildsettings/auditlogpane.cpp:482 +#: src/windows/guildsettings/auditlogpane.cpp:507 +msgid "Set auto archive duration to %1 minutes" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:490 +#: src/windows/guildsettings/auditlogpane.cpp:515 +msgid "Locked the thread, restricting it to only be unarchived by moderators" +msgstr "" +"Bloqueou a thread, restringindo-a a ser desarquivada apenas por moderadores" + +#: src/windows/guildsettings/auditlogpane.cpp:490 +#: src/windows/guildsettings/auditlogpane.cpp:515 +msgid "Unlocked the thread, allowing it to be unarchived by non-moderators" +msgstr "" +"Desbloqueou a thread, permitindo-a ser desarquivada por não-moderadores " + +#: src/windows/guildsettings/auditlogpane.cpp:496 +msgid "%1 made changes to the thread %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:521 +msgid "%1 deleted the thread %2" +msgstr "" + +#: src/windows/guildsettings/auditlogpane.cpp:525 +msgid "Unknown action" +msgstr "Ação desconhecida" + +#: src/windows/guildsettings/auditlogpane.cpp:533 +msgid "Reason: %1" +msgstr "" + +#: src/windows/guildsettings/banspane.cpp:12 +msgid "Unban" +msgstr "Desbanir" + +#: src/windows/guildsettings/banspane.cpp:31 +msgid "" +"You do not have permission to see bans. However, bans made while you are " +"connected will appear here" +msgstr "" +"Você não possui permissões para ver os banimentos. No entanto, banimentos " +"feitos enquanto você está conectado vão aparecer aqui" + +#: src/windows/guildsettings/banspane.cpp:55 +msgid "User" +msgstr "Usuário" + +#: src/windows/guildsettings/banspane.cpp:56 +msgid "Reason" +msgstr "Motivo" + +#: src/windows/guildsettings/banspane.cpp:100 +msgid "Failed to unban user" +msgstr "Falhou em desbanir usuário" + +#: src/windows/guildsettings/emojispane.cpp:17 +#: src/windows/guildsettings/invitespane.cpp:12 +msgid "Delete" +msgstr "Apagar" + +#: src/windows/guildsettings/emojispane.cpp:19 +msgid "Copy Emoji URL" +msgstr "Copiar URL do emoji" + +#: src/windows/guildsettings/emojispane.cpp:20 +msgid "Open in Browser" +msgstr "Abrir no Navegador" + +#: src/windows/guildsettings/emojispane.cpp:48 +#: src/windows/guildsettings/memberspane.cpp:64 +#: src/windows/guildsettings/rolespane.cpp:118 +msgid "Filter" +msgstr "Filtro" + +#: src/windows/guildsettings/emojispane.cpp:68 +msgid "Emoji" +msgstr "Emoji" + +#: src/windows/guildsettings/emojispane.cpp:76 +#: src/windows/guildsettings/emojispane.cpp:98 +msgid "Name" +msgstr "Nome" + +#: src/windows/guildsettings/emojispane.cpp:100 +msgid "Creator" +msgstr "Criador" + +#: src/windows/guildsettings/emojispane.cpp:101 +msgid "Is Animated?" +msgstr "É Animado?" + +#: src/windows/guildsettings/emojispane.cpp:132 +#: src/windows/guildsettings/emojispane.cpp:136 +#: src/windows/guildsettings/emojispane.cpp:138 +#: src/windows/guildsettings/emojispane.cpp:222 +#: src/windows/guildsettings/emojispane.cpp:230 +#: src/windows/guildsettings/invitespane.cpp:75 +msgid "Yes" +msgstr "Sim" + +#: src/windows/guildsettings/emojispane.cpp:132 +#: src/windows/guildsettings/emojispane.cpp:134 +#: src/windows/guildsettings/emojispane.cpp:136 +#: src/windows/guildsettings/invitespane.cpp:75 +msgid "No" +msgstr "Não" + +#: src/windows/guildsettings/emojispane.cpp:186 +msgid "Failed to set emoji name" +msgstr "Falhou em definir um nome para o emoji" + +#: src/windows/guildsettings/emojispane.cpp:206 +msgid "Are you sure you want to delete %1?" +msgstr "" + +#: src/windows/guildsettings/emojispane.cpp:209 +msgid "Failed to delete emoji" +msgstr "Falhou em deletar emoji" + +#: src/windows/guildsettings/infopane.cpp:15 +msgid "Guild name" +msgstr "Nome do Servidor" + +#: src/windows/guildsettings/infopane.cpp:37 +msgid "Press enter or lose focus to submit" +msgstr "Pressione enter para desfocar ou enviar" + +#: src/windows/guildsettings/infopane.cpp:53 +msgid "Click to choose a file, right click to paste" +msgstr "Clique para escolher um arquivo, clique no botão direito para copiar" + +#: src/windows/guildsettings/infopane.cpp:109 +msgid "Failed to set guild name" +msgstr "Falhou em definir um nome de guilda" + +#: src/windows/guildsettings/infopane.cpp:123 +msgid "Failed to set guild icon" +msgstr "Falhou em definir um ícone de guilda" + +#: src/windows/guildsettings/infopane.cpp:147 +msgid "Choose new guild icon" +msgstr "Escolha um novo ícone de guilda" + +#: src/windows/guildsettings/infopane.cpp:170 +msgid "Supported images" +msgstr "Extensões de Imagens Suportadas" + +#: src/windows/guildsettings/infopane.cpp:183 +msgid "All files" +msgstr "Todos os Arquivos" + +#: src/windows/guildsettings/invitespane.cpp:34 +msgid "Code" +msgstr "Código" + +#: src/windows/guildsettings/invitespane.cpp:35 +msgid "Expires" +msgstr "Vence" + +#: src/windows/guildsettings/invitespane.cpp:36 +msgid "Created by" +msgstr "Criado por" + +#: src/windows/guildsettings/invitespane.cpp:37 +msgid "Uses" +msgstr "Usos" + +#: src/windows/guildsettings/invitespane.cpp:38 +msgid "Max uses" +msgstr "Número de usos máximo" + +#: src/windows/guildsettings/invitespane.cpp:39 +msgid "Grants temporary membership" +msgstr "Concede associação temporária" + +#: src/windows/guildsettings/invitespane.cpp:64 +msgid "Never" +msgstr "Nunca" + +#: src/windows/guildsettings/invitespane.cpp:71 +msgid "Unlimited" +msgstr "Ilimitado" + +#: src/windows/guildsettings/invitespane.cpp:106 +msgid "Failed to delete invite" +msgstr "Falhou em apagar convite" + +#: src/windows/guildsettings/memberspane.cpp:20 +msgid "Some members may not be shown if the client is not aware of them" +msgstr "" +"Alguns membros podem não ser listados se o cliente não estiver consciente da " +"existência deles" + +#: src/windows/guildsettings/memberspane.cpp:178 +msgid "User is a bot" +msgstr "Usuário é um robô" + +#: src/windows/guildsettings/memberspane.cpp:213 +msgid "User ID: " +msgstr "ID de Usuário" + +#: src/windows/guildsettings/memberspane.cpp:216 +msgid "Joined server: " +msgstr "Entrou no servidor: " + +#: src/windows/guildsettings/memberspane.cpp:218 +msgid "Joined server: Unknown" +msgstr "Entrou no servidor: ???" + +#: src/windows/guildsettings/memberspane.cpp:219 +msgid "Nickname: " +msgstr "Apelido: " + +#: src/windows/guildsettings/memberspane.cpp:222 +msgid "Boosting since %1" +msgstr "" + +#: src/windows/guildsettings/rolespane.cpp:71 +msgid "Failed to set role position" +msgstr "Falhou em definir posição do cargo" + +#: src/windows/guildsettings/rolespane.cpp:217 +msgid "Press enter to submit" +msgstr "Pressione enter para enviar" + +#: src/windows/guildsettings/rolespane.cpp:236 +msgid "Failed to set role color" +msgstr "Falhou em definir cor do cargo" + +#: src/windows/guildsettings/rolespane.cpp:267 +msgid "General" +msgstr "Geral" + +#: src/windows/guildsettings/rolespane.cpp:277 +msgid "Text Channels" +msgstr "Canais de Texto" + +#: src/windows/guildsettings/rolespane.cpp:295 +msgid "Membership" +msgstr "Associação" + +#: src/windows/guildsettings/rolespane.cpp:303 +msgid "Advanced" +msgstr "Avançado" + +#: src/windows/guildsettings/rolespane.cpp:305 +msgid "Voice Channels" +msgstr "Canais de Voz" + +#: src/windows/guildsettings/rolespane.cpp:319 +msgid "Events" +msgstr "Eventos" + +#: src/windows/guildsettings/rolespane.cpp:412 +msgid "Failed to set role name" +msgstr "Falhou em definir o nome de um cargo" + +#: src/windows/voice/voicewindow.cpp:23 +msgid "Deafen" +msgstr "Ensurdecer" + +#: src/windows/voice/voicewindow.cpp:24 +msgid "Suppress Noise" +msgstr "Suprimir Ruído" + +#: src/windows/voice/voicewindow.cpp:25 +msgid "Mix Mono" +msgstr "Mixagem Mono" + +#: src/windows/voice/voicewindow.cpp:26 src/windows/voice/voicewindow.cpp:381 +msgid "Request to Speak" +msgstr "Pedir para Falar" + +#: src/windows/voice/voicewindow.cpp:28 +msgid "You've been invited to speak" +msgstr "Voce foi convidado para subir no palco" + +#: src/windows/voice/voicewindow.cpp:30 +msgid "Decline" +msgstr "Recusar" + +#: src/windows/voice/voicewindow.cpp:33 +msgid "More _Settings" +msgstr "Mais _Configurações" + +#: src/windows/voice/voicewindow.cpp:97 +msgid "" +"Voice Activation Detection method\n" +"Gate - Simple volume threshold. Slider changes threshold\n" +"RNNoise - Heavier on CPU. Slider changes probability threshold" +msgstr "" +"Método de detecção de ativação de voz\n" +"Gate - Limite de volume simples. O controle deslizante altera o limite\n" +"RNNoise - Mais pesado na CPU. O controle deslizante altera o limite de " +"probabilidade" + +#: src/windows/voice/voicewindow.cpp:180 +msgid "Threshold" +msgstr "Limite" + +#: src/windows/voice/voicewindow.cpp:190 +msgid "VAD Method" +msgstr "Método VAD" + +#: src/windows/voice/voicewindow.cpp:191 +msgid "Output Device" +msgstr "Dispositivo de Saída" + +#: src/windows/voice/voicewindow.cpp:192 +msgid "Input Device" +msgstr "Dispositivo de Entrada" + +#: src/windows/voice/voicewindow.cpp:235 +msgid "Speakers" +msgstr "Falantes" + +#: src/windows/voice/voicewindow.cpp:238 +msgid "Audience" +msgstr "Audiência" + +#: src/windows/voice/voicewindow.cpp:259 +msgid "Input Settings" +msgstr "Configurações de Entrada" + +#: src/windows/voice/voicewindow.cpp:373 +msgid "Leave the Stage" +msgstr "Sair do Palco" + +#: src/windows/voice/voicewindow.cpp:375 +msgid "Speak on Stage" +msgstr "Falar no Palco" + +#: src/windows/voice/voicewindow.cpp:377 +msgid "Cancel Request" +msgstr "Cancelar Pedido" + +#: src/windows/voice/voicewindow.cpp:379 +msgid "Decline Invite" +msgstr "Recusar Convite" + +#: src/windows/voice/voicewindow.cpp:386 +msgid "Topic: " +msgstr "Tópico: " + +#, c++-format +#~ msgid "Originally known as {}" +#~ msgstr "Originalmente conhecido como {}" + +#, c++-format +#~ msgid "#{} - Threads" +#~ msgstr "#{} - Threads" + +#, c++-format +#~ msgid "Are you sure you want to delete {}?" +#~ msgstr "Você tem certeza de que quer deletar {}?" + +#, c++-format +#~ msgid "Boosting since {}" +#~ msgstr "Impulsionando desde {}" + +#, c++-format +#~ msgid "{} made changes to {}" +#~ msgstr "{} fez mudanças em {}" + +#, c++-format +#~ msgid "Set the server name to {}" +#~ msgstr "Definiu o nome do servidor como {}" + +#, c++-format +#~ msgid "{} created a voice channel #{}" +#~ msgstr "{} criou um canal de voz #{}" + +#, c++-format +#~ msgid "{} created a text channel #{}" +#~ msgstr "{} criou um canal de texto #{}" + +#, c++-format +#~ msgid "Set the name to {}" +#~ msgstr "Mudou o nome para {}" + +#, c++-format +#~ msgid "{} made changes to #{}" +#~ msgstr "{} fez mudanças em #{}" + +#, c++-format +#~ msgid "{} made changes to <#{}>" +#~ msgstr "{} fez mudanças em <#{}>" + +#, c++-format +#~ msgid "Changed the name from {} to {}" +#~ msgstr "Alterou o nome de {} para {}" + +#, c++-format +#~ msgid "Changed the name to {}" +#~ msgstr "Alterou o nome para {}" + +#, c++-format +#~ msgid "Changed the topic to {}" +#~ msgstr "Mudou o tópico para {}" + +#, c++-format +#~ msgid "Set slowmode to {} seconds" +#~ msgstr "Definiu o temporizador do câmera lenta para {} segundos" + +#, c++-format +#~ msgid "{} removed #{}" +#~ msgstr "{} removeu #{}" + +#, c++-format +#~ msgid "{} created channel overrides for #{}" +#~ msgstr "{} criou substituições de canal para #{}" + +#, c++-format +#~ msgid "{} created channel overrides for <#{}>" +#~ msgstr "{} criou substituições de canal para <#{}>" + +#, c++-format +#~ msgid "{} updated channel overrides for #{}" +#~ msgstr "{} atualizou substituições de canal para #{}" + +#, c++-format +#~ msgid "{} updated channel overrides for <#{}>" +#~ msgstr "{} atualizou substituições de canal para <#{}>" + +#, c++-format +#~ msgid "{} removed channel overrides for #{}" +#~ msgstr "{} removeu substituições de canal para #{}" + +#, c++-format +#~ msgid "{} removed channel overrides for <#{}>" +#~ msgstr "{} removeu substituições de canal para <#{}>" + +#, c++-format +#~ msgid "{} kicked {}" +#~ msgstr "{} expulsou {}" + +#, c++-format +#~ msgid "{} pruned {} members" +#~ msgstr "{} podou {} membros" + +#, c++-format +#~ msgid "For {} days of inactivity" +#~ msgstr "Por {} dias de inatividade" + +#, c++-format +#~ msgid "{} banned {}" +#~ msgstr "{} baniu {}" + +#, c++-format +#~ msgid "{} removed the ban for {}" +#~ msgstr "{} removeu o banimento de {}" + +#, c++-format +#~ msgid "{} updated {}" +#~ msgstr "{} atualizou {}" + +#, c++-format +#~ msgid "Set their nickname to {}" +#~ msgstr "Definiu o apelido para {}" + +#, c++-format +#~ msgid "{} updated roles for {}" +#~ msgstr "{} atualizou os cargos de {}" + +#, c++-format +#~ msgid "Removed a role {}" +#~ msgstr "Removeu o cargo {}" + +#, c++-format +#~ msgid "Added a role {}" +#~ msgstr "Adicionou o cargo {}" + +#, c++-format +#~ msgid "{} moved a user to {}" +#~ msgstr "{} moveu um usuário para {}" + +#, c++-format +#~ msgid "{} moved {} users to {}" +#~ msgstr "{} moveu {} usuários para {}" + +#, c++-format +#~ msgid "{} disconnected {} users from voice" +#~ msgstr "{} desconectou {} usuários de canais de voz" + +#, c++-format +#~ msgid "{} added {} to the server" +#~ msgstr "{} adicionou {} ao servidor" + +#, c++-format +#~ msgid "{} created the role {}" +#~ msgstr "{} criou o cargo {}" + +#, c++-format +#~ msgid "{} updated the role {}" +#~ msgstr "{} atualizou o cargo {}" + +#, c++-format +#~ msgid "Set the color to {}" +#~ msgstr "Definiu a cor para {}" + +#, c++-format +#~ msgid "{} deleted the role {}" +#~ msgstr "{} deletou o cargo {}" + +#, c++-format +#~ msgid "{} created an invite {}" +#~ msgstr "{} criou um convite {}" + +#, c++-format +#~ msgid "For channel {}" +#~ msgstr "Para o canal {}" + +#, c++-format +#~ msgid "Which has {} uses" +#~ msgstr "O qual possui {} usos" + +#, c++-format +#~ msgid "{} deleted an invite {}" +#~ msgstr "{} apagou um convite {}" + +#, c++-format +#~ msgid "{} created the webhook {}" +#~ msgstr "{} criou um webhook {}" + +#, c++-format +#~ msgid "With channel #{}" +#~ msgstr "Com o canal #{}" + +#, c++-format +#~ msgid "{} updated the webhook {}" +#~ msgstr "{} atualizou o webhook {}" + +#, c++-format +#~ msgid "{} updated a webhook" +#~ msgstr "{} atualizou um webhook" + +#, c++-format +#~ msgid "Changed the channel to #{}" +#~ msgstr "Mudou o canal para #{}" + +#, c++-format +#~ msgid "{} deleted the webhook {}" +#~ msgstr "{} apagou o webhook {}" + +#, c++-format +#~ msgid "{} created the emoji {}" +#~ msgstr "{} criou o emoji {}" + +#, c++-format +#~ msgid "{} updated the emoji {}" +#~ msgstr "{} atualizou o emoji {}" + +#, c++-format +#~ msgid "{} deleted the emoji {}" +#~ msgstr "{} apagou o emoji {}" + +#, c++-format +#~ msgid "{} deleted {} messages in #{}" +#~ msgstr "{} apagou {} mensagens em #{}" + +#, c++-format +#~ msgid "{} deleted {} messages" +#~ msgstr "{} apagou {} mensagens" + +#, c++-format +#~ msgid "{} pinned a message by {}" +#~ msgstr "{} fixou uma mensagem de {}" + +#, c++-format +#~ msgid "{} unpinned a message by {}" +#~ msgstr "{} desafixar uma mensagem de {}" + +#, c++-format +#~ msgid "{} started the stage for {}" +#~ msgstr "{} iniciou o palco para {}" + +#, c++-format +#~ msgid "Set the topic to {}" +#~ msgstr "Definiu o tópico para {}" + +#, c++-format +#~ msgid "Set the privacy level to {}" +#~ msgstr "Definiu o nível de privacidade para {}" + +#, c++-format +#~ msgid "{} updated the stage for {}" +#~ msgstr "{} atualizou o palco para {}" + +#, c++-format +#~ msgid "{} ended the stage for {}" +#~ msgstr "{} encerrou o palco para {}" + +#, c++-format +#~ msgid "{} created a thread {}" +#~ msgstr "{} criou uma thread {}" + +#, c++-format +#~ msgid "Set auto archive duration to {} minutes" +#~ msgstr "" +#~ "Definiu o intervalo para o arquivamento automático para {} minutos" + +#, c++-format +#~ msgid "{} made changes to the thread {}" +#~ msgstr "{} fez mudanças na thread {}" + +#, c++-format +#~ msgid "{} deleted the thread {}" +#~ msgstr "{} apagou a thread {}" + +#, c++-format +#~ msgid "Reason: {}" +#~ msgstr "Motivo: {}" + +#~ msgid "Gate" +#~ msgstr "Gate" + +#~ msgid "RNNoise" +#~ msgstr "RNNoise" + +#~ msgid "{} created channel overrides for #{}" +#~ msgstr "{} criou subsituições de canal para #{}" + +#~ msgid "{} created channel overrides for <#{}>" +#~ msgstr "{} criou subsituições de canal para <#{}>" + +#~ msgid "{} updated channel overrides for #{}" +#~ msgstr "{} atualizou as substituições de canal para #{}" + +#~ msgid "{} updated channel overrides for <#{}>" +#~ msgstr "{} atualizou as substituições de canal para <#{}>" + +#~ msgid "{} removed channel overrides for #{}" +#~ msgstr "{} removeu as substituições de canal para #{}" + +#~ msgid "{} removed channel overrides for <#{}>" +#~ msgstr "{} removeu as substituições de canal para #{}" + +#~ msgid "" +#~ "{} just boosted the server {} times! {} " +#~ "has achieved Level {}}!" +#~ msgstr "" +#~ "{} acabou de impulsionar o servidor {} " +#~ "vezes! {} atingiu nível {}}!" + +#~ msgid "{} made changes to the thread " +#~ msgstr "{} fez mudanças para a thread {}" + +#~ msgid " is typing..." +#~ msgstr " está digitando..." + +#~ msgid " and " +#~ msgstr " e " + +#~ msgid " are typing..." +#~ msgstr " estão digitando..." + +#~ msgid "and " +#~ msgstr "e " + +#~ msgid "css failed parsing (" +#~ msgstr "CSS falhou" + +#~ msgid "Lost connection with Discord's gateway. Try reconnecting (code " +#~ msgstr "Conexão com o gateway do discord perdida. Tente reconectar (código" + +#~ msgid "Are you sure you want to leave " +#~ msgstr "Você tem certeza de que quer sair " + +#~ msgid "Are you sure you want to kick " +#~ msgstr "Você tem certeza de que quer expulsar " + +#~ msgid "Are you sure you want to ban " +#~ msgstr "Você tem certeza de que quer banir " + +#~ msgid "css failed to load (" +#~ msgstr "css falhou em carregar (" diff --git a/src/abaddon.cpp b/src/abaddon.cpp index 653327cd..2dafd490 100644 --- a/src/abaddon.cpp +++ b/src/abaddon.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "platform.hpp" #include "audio/manager.hpp" #include "discord/discord.hpp" @@ -211,7 +212,7 @@ int Abaddon::StartGTK() { m_css_provider = Gtk::CssProvider::create(); m_css_provider->signal_parsing_error().connect([](const Glib::RefPtr §ion, const Glib::Error &error) { - Gtk::MessageDialog dlg("css failed parsing (" + error.what() + ")", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(Glib::ustring::compose(_("css failed parsing (%1)"), error.what()), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); }); @@ -227,13 +228,13 @@ int Abaddon::StartGTK() { } if (!png_found) { - Gtk::MessageDialog dlg("The PNG pixbufloader wasn't detected. Abaddon may not work as a result.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("The PNG pixbufloader wasn't detected. Abaddon may not work as a result."), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } if (!gif_found) { - Gtk::MessageDialog dlg("The GIF pixbufloader wasn't detected. Animations may not display as a result.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("The GIF pixbufloader wasn't detected. Animations may not display as a result."), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -248,19 +249,19 @@ int Abaddon::StartGTK() { #endif if (!m_settings.IsValid()) { - Gtk::MessageDialog dlg(*m_main_window, "The settings file could not be opened!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*m_main_window, _("The settings file could not be opened!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } if (!m_emojis.Load()) { - Gtk::MessageDialog dlg(*m_main_window, "The emoji file couldn't be loaded!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*m_main_window, _("The emoji file couldn't be loaded!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } if (!m_discord.IsStoreValid()) { - Gtk::MessageDialog dlg(*m_main_window, "The Discord cache could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*m_main_window, _("The Discord cache could not be created!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); return 1; @@ -268,7 +269,7 @@ int Abaddon::StartGTK() { #ifdef WITH_VOICE if (!m_audio.OK()) { - Gtk::MessageDialog dlg(*m_main_window, "The audio engine could not be initialized!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*m_main_window, _("The audio engine could not be initialized!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -329,7 +330,7 @@ int Abaddon::StartGTK() { m_tray->signal_popup_menu().connect(sigc::mem_fun(*this, &Abaddon::on_tray_popup_menu)); } m_tray_menu = Gtk::make_managed(); - m_tray_exit = Gtk::make_managed("Quit", false); + m_tray_exit = Gtk::make_managed(_("Quit"), false); m_tray_exit->signal_activate().connect(sigc::mem_fun(*this, &Abaddon::on_tray_menu_click)); @@ -464,12 +465,12 @@ void Abaddon::DiscordOnDisconnect(bool is_reconnecting, GatewayCloseCode close_c m_main_window->UpdateComponents(); if (close_code == GatewayCloseCode::AuthenticationFailed) { - Gtk::MessageDialog dlg(*m_main_window, "Discord rejected your token", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*m_main_window, _("Discord rejected your token"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } else if (close_code != GatewayCloseCode::Normal) { Gtk::MessageDialog dlg(*m_main_window, - "Lost connection with Discord's gateway. Try reconnecting (code " + std::to_string(static_cast(close_code)) + ")", + Glib::ustring::compose(_("Lost connection with Discord's gateway. Try reconnecting (code %1)"), static_cast(close_code)), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); @@ -479,7 +480,7 @@ void Abaddon::DiscordOnDisconnect(bool is_reconnecting, GatewayCloseCode close_c void Abaddon::DiscordOnThreadUpdate(const ThreadUpdateData &data) { if (data.Thread.ID == m_main_window->GetChatActiveChannel()) { if (data.Thread.ThreadMetadata->IsArchived) - m_main_window->GetChatWindow()->SetTopic("This thread is archived. Sending a message will unarchive it"); + m_main_window->GetChatWindow()->SetTopic(_("This thread is archived. Sending a message will unarchive it")); else m_main_window->GetChatWindow()->SetTopic(""); } @@ -622,7 +623,7 @@ void Abaddon::RunFirstTimeDiscordStartup() { m_discord.SetCookie(*cookie); } else { ConfirmDialog confirm(*m_main_window); - confirm.SetConfirmText("Cookies could not be fetched. This may increase your chances of being flagged by Discord's anti-spam"); + confirm.SetConfirmText(_("Cookies could not be fetched. This may increase your chances of being flagged by Discord's anti-spam")); confirm.SetAcceptOnly(true); confirm.run(); } @@ -631,7 +632,7 @@ void Abaddon::RunFirstTimeDiscordStartup() { m_discord.SetBuildNumber(*build_number); } else { ConfirmDialog confirm(*m_main_window); - confirm.SetConfirmText("Build number could not be fetched. This may increase your chances of being flagged by Discord's anti-spam"); + confirm.SetConfirmText(_("Build number could not be fetched. This may increase your chances of being flagged by Discord's anti-spam")); confirm.SetAcceptOnly(true); confirm.run(); } @@ -648,7 +649,7 @@ void Abaddon::ShowGuildVerificationGateDialog(Snowflake guild_id) { if (dlg.run() == Gtk::RESPONSE_OK) { const auto cb = [this](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg(*m_main_window, "Failed to accept the verification gate.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*m_main_window, _("Failed to accept the verification gate."), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -673,14 +674,14 @@ void Abaddon::CheckMessagesForMembers(const ChannelData &chan, const std::vector void Abaddon::SetupUserMenu() { m_user_menu = Gtk::manage(new Gtk::Menu); - m_user_menu_insert_mention = Gtk::manage(new Gtk::MenuItem("Insert Mention")); - m_user_menu_ban = Gtk::manage(new Gtk::MenuItem("Ban")); - m_user_menu_kick = Gtk::manage(new Gtk::MenuItem("Kick")); - m_user_menu_copy_id = Gtk::manage(new Gtk::MenuItem("Copy ID")); - m_user_menu_open_dm = Gtk::manage(new Gtk::MenuItem("Go to DM")); - m_user_menu_roles = Gtk::manage(new Gtk::MenuItem("Roles")); - m_user_menu_info = Gtk::manage(new Gtk::MenuItem("View Profile")); - m_user_menu_remove_recipient = Gtk::manage(new Gtk::MenuItem("Remove From Group")); + m_user_menu_insert_mention = Gtk::manage(new Gtk::MenuItem(_("Insert Mention"))); + m_user_menu_ban = Gtk::manage(new Gtk::MenuItem(_("Ban"))); + m_user_menu_kick = Gtk::manage(new Gtk::MenuItem(_("Kick"))); + m_user_menu_copy_id = Gtk::manage(new Gtk::MenuItem(_("Copy ID"))); + m_user_menu_open_dm = Gtk::manage(new Gtk::MenuItem(_("Go to DM"))); + m_user_menu_roles = Gtk::manage(new Gtk::MenuItem(_("Roles"))); + m_user_menu_info = Gtk::manage(new Gtk::MenuItem(_("View Profile"))); + m_user_menu_remove_recipient = Gtk::manage(new Gtk::MenuItem(_("Remove From Group"))); m_user_menu_roles_submenu = Gtk::manage(new Gtk::Menu); m_user_menu_roles->set_submenu(*m_user_menu_roles_submenu); m_user_menu_insert_mention->signal_activate().connect(sigc::mem_fun(*this, &Abaddon::on_user_menu_insert_mention)); @@ -922,7 +923,7 @@ void Abaddon::ActionChannelOpened(Snowflake id, bool expand_to) { if (channel->IsThread()) { m_discord.SendThreadLazyLoad(id); if (channel->ThreadMetadata->IsArchived) - m_main_window->GetChatWindow()->SetTopic("This thread is archived. Sending a message will unarchive it"); + m_main_window->GetChatWindow()->SetTopic(_("This thread is archived. Sending a message will unarchive it")); } else if (channel->Type != ChannelType::DM && channel->Type != ChannelType::GROUP_DM && channel->GuildID.has_value()) { m_discord.SendLazyLoad(id); @@ -998,7 +999,7 @@ void Abaddon::ActionLeaveGuild(Snowflake id) { ConfirmDialog dlg(*m_main_window); const auto guild = m_discord.GetGuild(id); if (guild.has_value()) - dlg.SetConfirmText("Are you sure you want to leave " + guild->Name + "?"); + dlg.SetConfirmText(Glib::ustring::compose(_("Are you sure you want to leave %1?"), guild->Name)); auto response = dlg.run(); if (response == Gtk::RESPONSE_OK) m_discord.LeaveGuild(id); @@ -1008,7 +1009,7 @@ void Abaddon::ActionKickMember(Snowflake user_id, Snowflake guild_id) { ConfirmDialog dlg(*m_main_window); const auto user = m_discord.GetUser(user_id); if (user.has_value()) - dlg.SetConfirmText("Are you sure you want to kick " + user->GetUsername() + "?"); + dlg.SetConfirmText(Glib::ustring::compose(_("Are you sure you want to kick %1?"), user->GetUsername())); auto response = dlg.run(); if (response == Gtk::RESPONSE_OK) m_discord.KickUser(user_id, guild_id); @@ -1018,7 +1019,7 @@ void Abaddon::ActionBanMember(Snowflake user_id, Snowflake guild_id) { ConfirmDialog dlg(*m_main_window); const auto user = m_discord.GetUser(user_id); if (user.has_value()) - dlg.SetConfirmText("Are you sure you want to ban " + user->GetUsername() + "?"); + dlg.SetConfirmText(Glib::ustring::compose(_("Are you sure you want to ban %1?"), user->GetUsername())); auto response = dlg.run(); if (response == Gtk::RESPONSE_OK) m_discord.BanUser(user_id, guild_id); @@ -1115,7 +1116,7 @@ void Abaddon::ActionReloadCSS() { m_css_provider->load_from_path(GetCSSPath("/" + GetSettings().MainCSS)); Gtk::StyleContext::add_provider_for_screen(Gdk::Screen::get_default(), m_css_provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); } catch (Glib::Error &e) { - Gtk::MessageDialog dlg(*m_main_window, "css failed to load (" + e.what() + ")", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*m_main_window, Glib::ustring::compose(_("css failed to load (%1)"), e.what()), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -1161,6 +1162,11 @@ int main(int argc, char **argv) { // windows doesnt have langinfo.h so some localization falls back to translation strings // i dont like the default translation so this lets us use strftime +// Mac building workaround +#ifdef setlocale +#undef setlocale +#endif + #ifdef _WIN32 char *systemLocale = std::setlocale(LC_ALL, ""); try { @@ -1191,6 +1197,13 @@ int main(int argc, char **argv) { auto log_discord = spdlog::stdout_color_mt("discord"); auto log_ra = spdlog::stdout_color_mt("remote-auth"); + bindtextdomain("abaddon", Platform::FindLocaleFolder().c_str()); + + // Necessary for correct utf-8 text rendering + bind_textdomain_codeset("abaddon", "utf-8"); + + textdomain("abaddon"); + Gtk::Main::init_gtkmm_internals(); // why??? return Abaddon::Get().StartGTK(); } diff --git a/src/components/channellist/channellisttree.cpp b/src/components/channellist/channellisttree.cpp index e824933c..f9708cff 100644 --- a/src/components/channellist/channellisttree.cpp +++ b/src/components/channellist/channellisttree.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "abaddon.hpp" @@ -15,34 +16,36 @@ ChannelListTree::ChannelListTree() , m_model(Gtk::TreeStore::create(m_columns)) , m_filter_model(Gtk::TreeModelFilter::create(m_model)) , m_sort_model(Gtk::TreeModelSort::create(m_filter_model)) - , m_menu_guild_copy_id("_Copy ID", true) - , m_menu_guild_settings("View _Settings", true) - , m_menu_guild_leave("_Leave", true) - , m_menu_guild_mark_as_read("Mark as _Read", true) - , m_menu_category_copy_id("_Copy ID", true) - , m_menu_channel_copy_id("_Copy ID", true) - , m_menu_channel_mark_as_read("Mark as _Read", true) + , m_menu_guild_copy_id(_("_Copy ID"), true) + , m_menu_guild_settings(_("View _Settings"), true) + , m_menu_guild_leave(_("_Leave"), true) + , m_menu_guild_mark_as_read(_("Mark as _Read"), true) + , m_menu_category_copy_id(_("_Copy ID"), true) + , m_menu_channel_copy_id(_("_Copy ID"), true) + , m_menu_channel_mark_as_read(_("Mark as _Read"), true) #ifdef WITH_LIBHANDY - , m_menu_channel_open_tab("Open in New _Tab", true) - , m_menu_dm_open_tab("Open in New _Tab", true) + , m_menu_channel_open_tab(_("Open in New _Tab"), true) + , m_menu_dm_open_tab(_("Open in New _Tab"), true) #endif - , m_menu_voice_channel_join("_Join", true) - , m_menu_voice_channel_disconnect("_Disconnect", true) - , m_menu_voice_stage_join("_Join", true) - , m_menu_voice_stage_disconnect("_Disconnect", true) - , m_menu_voice_channel_mark_as_read("Mark as _Read", true) - , m_menu_voice_open_chat("Open _Chat", true) - , m_menu_dm_copy_id("_Copy ID", true) +#ifdef WITH_VOICE + , m_menu_voice_channel_join(_("_Join"), true) + , m_menu_voice_channel_disconnect(_("_Disconnect"), true) + , m_menu_voice_stage_join(_("_Join"), true) + , m_menu_voice_stage_disconnect(_("_Disconnect"), true) + , m_menu_voice_channel_mark_as_read(_("Mark as _Read"), true) + , m_menu_voice_open_chat(_("Open _Chat"), true) + , m_menu_dm_copy_id(_("_Copy ID"), true) , m_menu_dm_close("") // changes depending on if group or not +#endif #ifdef WITH_VOICE - , m_menu_dm_join_voice("Join _Voice", true) - , m_menu_dm_disconnect_voice("_Disconnect Voice", true) + , m_menu_dm_join_voice(_("Join _Voice"), true) + , m_menu_dm_disconnect_voice(_("_Disconnect Voice"), true) #endif - , m_menu_thread_copy_id("_Copy ID", true) - , m_menu_thread_leave("_Leave", true) - , m_menu_thread_archive("_Archive", true) - , m_menu_thread_unarchive("_Unarchive", true) - , m_menu_thread_mark_as_read("Mark as _Read", true) { + , m_menu_thread_copy_id(_("_Copy ID"), true) + , m_menu_thread_leave(_("_Leave"), true) + , m_menu_thread_archive(_("_Archive"), true) + , m_menu_thread_unarchive(_("_Unarchive"), true) + , m_menu_thread_mark_as_read(_("Mark as _Read"), true) { get_style_context()->add_class("channel-list"); // Filter iters @@ -253,7 +256,7 @@ ChannelListTree::ChannelListTree() if (channel->Type == ChannelType::DM) discord.CloseDM(id); - else if (Abaddon::Get().ShowConfirm("Are you sure you want to leave this group DM?")) + else if (Abaddon::Get().ShowConfirm(_("Are you sure you want to leave this group DM?"))) Abaddon::Get().GetDiscordClient().CloseDM(id); }); m_menu_dm_toggle_mute.signal_activate().connect([this] { @@ -291,7 +294,7 @@ ChannelListTree::ChannelListTree() Gtk::Clipboard::get()->set_text(std::to_string((*m_model->get_iter(m_path_for_menu))[m_columns.m_id])); }); m_menu_thread_leave.signal_activate().connect([this] { - if (Abaddon::Get().ShowConfirm("Are you sure you want to leave this thread?")) + if (Abaddon::Get().ShowConfirm(_("Are you sure you want to leave this thread?"))) Abaddon::Get().GetDiscordClient().LeaveThread(static_cast((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]), "Context%20Menu", [](...) {}); }); m_menu_thread_archive.signal_activate().connect([this] { @@ -1193,7 +1196,7 @@ void ChannelListTree::AddPrivateChannels() { auto header_row = *m_model->append(); header_row[m_columns.m_type] = RenderType::DMHeader; header_row[m_columns.m_sort] = -1; - header_row[m_columns.m_name] = "Direct Messages"; + header_row[m_columns.m_name] = fmt::format("{}", _("Direct Messages")); m_dm_header = m_model->get_path(header_row); auto &discord = Abaddon::Get().GetDiscordClient(); @@ -1365,7 +1368,7 @@ bool ChannelListTree::OnButtonPressEvent(GdkEventButton *ev) { OnDMSubmenuPopup(); const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(static_cast(row[m_columns.m_id])); if (channel.has_value()) { - m_menu_dm_close.set_label(channel->Type == ChannelType::DM ? "Close" : "Leave"); + m_menu_dm_close.set_label(channel->Type == ChannelType::DM ? _("Close") : _("Leave")); m_menu_dm_close.show(); } else m_menu_dm_close.hide(); @@ -1419,9 +1422,9 @@ void ChannelListTree::OnGuildSubmenuPopup() { const auto id = static_cast((*iter)[m_columns.m_id]); auto &discord = Abaddon::Get().GetDiscordClient(); if (discord.IsGuildMuted(id)) - m_menu_guild_toggle_mute.set_label("Unmute"); + m_menu_guild_toggle_mute.set_label(_("Unmute")); else - m_menu_guild_toggle_mute.set_label("Mute"); + m_menu_guild_toggle_mute.set_label(_("Mute")); const auto guild = discord.GetGuild(id); const auto self_id = discord.GetUserData().ID; @@ -1433,9 +1436,9 @@ void ChannelListTree::OnCategorySubmenuPopup() { if (!iter) return; const auto id = static_cast((*iter)[m_columns.m_id]); if (Abaddon::Get().GetDiscordClient().IsChannelMuted(id)) - m_menu_category_toggle_mute.set_label("Unmute"); + m_menu_category_toggle_mute.set_label(_("Unmute")); else - m_menu_category_toggle_mute.set_label("Mute"); + m_menu_category_toggle_mute.set_label(_("Mute")); } void ChannelListTree::OnChannelSubmenuPopup() { @@ -1448,9 +1451,9 @@ void ChannelListTree::OnChannelSubmenuPopup() { m_menu_channel_open_tab.set_sensitive(perms); #endif if (discord.IsChannelMuted(id)) - m_menu_channel_toggle_mute.set_label("Unmute"); + m_menu_channel_toggle_mute.set_label(("Unmute")); else - m_menu_channel_toggle_mute.set_label("Mute"); + m_menu_channel_toggle_mute.set_label(("Mute")); } void ChannelListTree::OnVoiceChannelSubmenuPopup() { @@ -1497,9 +1500,9 @@ void ChannelListTree::OnDMSubmenuPopup() { const auto id = static_cast((*iter)[m_columns.m_id]); auto &discord = Abaddon::Get().GetDiscordClient(); if (discord.IsChannelMuted(id)) - m_menu_dm_toggle_mute.set_label("Unmute"); + m_menu_dm_toggle_mute.set_label(_("Unmute")); else - m_menu_dm_toggle_mute.set_label("Mute"); + m_menu_dm_toggle_mute.set_label(_("Mute")); #ifdef WITH_VOICE if (discord.IsVoiceConnected() || discord.IsVoiceConnecting()) { @@ -1522,9 +1525,9 @@ void ChannelListTree::OnThreadSubmenuPopup() { const auto id = static_cast((*iter)[m_columns.m_id]); if (discord.IsChannelMuted(id)) - m_menu_thread_toggle_mute.set_label("Unmute"); + m_menu_thread_toggle_mute.set_label(_("Unmute")); else - m_menu_thread_toggle_mute.set_label("Mute"); + m_menu_thread_toggle_mute.set_label(_("Mute")); auto channel = discord.GetChannel(id); if (!channel.has_value() || !channel->ThreadMetadata.has_value()) return; diff --git a/src/components/chatinput.cpp b/src/components/chatinput.cpp index 1fcf6288..46d16219 100644 --- a/src/components/chatinput.cpp +++ b/src/components/chatinput.cpp @@ -1,5 +1,6 @@ #include "chatinput.hpp" #include +#include #include #include #include "abaddon.hpp" @@ -139,7 +140,7 @@ ChatInputTextContainer::ChatInputTextContainer() { } void ChatInputTextContainer::ShowFileChooser() { - auto dlg = Gtk::FileChooserNative::create("Choose file", Gtk::FILE_CHOOSER_ACTION_OPEN); + auto dlg = Gtk::FileChooserNative::create(_("Choose file"), Gtk::FILE_CHOOSER_ACTION_OPEN); dlg->set_select_multiple(true); dlg->set_modal(true); @@ -385,14 +386,14 @@ void ChatInputAttachmentItem::SetFilenameFromFile() { } void ChatInputAttachmentItem::SetupMenu() { - m_menu_remove.set_label("Remove"); + m_menu_remove.set_label(_("Remove")); m_menu_remove.signal_activate().connect([this] { m_signal_item_removed.emit(); }); - m_menu_set_filename.set_label("Change Filename"); + m_menu_set_filename.set_label(_("Change Filename")); m_menu_set_filename.signal_activate().connect([this] { - const auto name = Abaddon::Get().ShowTextPrompt("Enter new filename for attachment", "Enter filename", m_filename); + const auto name = Abaddon::Get().ShowTextPrompt(_("Enter new filename for attachment"), _("Enter filename"), m_filename); if (name.has_value()) { m_filename = *name; m_label.set_text(m_filename); @@ -400,9 +401,9 @@ void ChatInputAttachmentItem::SetupMenu() { } }); - m_menu_set_alt_text.set_label("Change Alt-Text"); + m_menu_set_alt_text.set_label(_("Change Alt-Text")); m_menu_set_alt_text.signal_activate().connect([this]() { - const auto description = Abaddon::Get().ShowTextPrompt("Enter description (alt-text) for attachment", "Enter alt-text", m_description); + const auto description = Abaddon::Get().ShowTextPrompt(_("Enter description (alt-text) for attachment"), _("Enter alt-text"), m_description); if (description.has_value()) { m_description = *description; } diff --git a/src/components/chatinputindicator.cpp b/src/components/chatinputindicator.cpp index 51d21421..3eb123b3 100644 --- a/src/components/chatinputindicator.cpp +++ b/src/components/chatinputindicator.cpp @@ -1,6 +1,8 @@ #include "chatinputindicator.hpp" #include +#include #include +#include #include "abaddon.hpp" #include "util.hpp" @@ -114,15 +116,20 @@ void ChatInputIndicator::ComputeTypingString() { if (typers.empty()) { SetTypingString(""); } else if (typers.size() == 1) { - SetTypingString(typers[0].GetDisplayName(m_active_guild) + " is typing..."); + SetTypingString(Glib::ustring::compose(_("%1 is typing..."), typers[0].GetDisplayName(m_active_guild))); } else if (typers.size() == 2) { - SetTypingString(typers[0].GetDisplayName(m_active_guild) + " and " + typers[1].GetDisplayName(m_active_guild) + " are typing..."); + SetTypingString(Glib::ustring::compose(_("%1 and %2 are typing"), + typers[0].GetDisplayName(m_active_guild), + typers[1].GetDisplayName(m_active_guild))); } else if (typers.size() > 2 && typers.size() <= MaxUsersInIndicator) { - Glib::ustring str; - for (size_t i = 0; i < typers.size() - 1; i++) - str += typers[i].GetDisplayName(m_active_guild) + ", "; - SetTypingString(str + "and " + typers[typers.size() - 1].GetDisplayName(m_active_guild) + " are typing..."); + // FIXME: Just because this suffice the case where 4 are typing, does not necessarily mean that there are exactly 4 people typing + Glib::ustring str = Glib::ustring::compose(_("%1, %2, %3 and %4 are typing..."), + typers[0].GetDisplayName(m_active_guild), + typers[1].GetDisplayName(m_active_guild), + typers[2].GetDisplayName(m_active_guild), + typers[3].GetDisplayName(m_active_guild)); + SetTypingString(str); } else { // size() > MaxUsersInIndicator - SetTypingString("Several people are typing..."); + SetTypingString(_("Several people are typing...")); } } diff --git a/src/components/chatlist.cpp b/src/components/chatlist.cpp index 3e22d72a..073c6ae1 100644 --- a/src/components/chatlist.cpp +++ b/src/components/chatlist.cpp @@ -1,3 +1,4 @@ +#include #include "chatlist.hpp" #include "abaddon.hpp" #include "chatmessage.hpp" @@ -294,28 +295,28 @@ std::optional ChatList::GetLastSentEditableMessage() { } void ChatList::SetupMenu() { - m_menu_copy_id = Gtk::manage(new Gtk::MenuItem("Copy ID")); + m_menu_copy_id = Gtk::manage(new Gtk::MenuItem(_("Copy ID"))); m_menu_copy_id->signal_activate().connect([this] { Gtk::Clipboard::get()->set_text(std::to_string(m_menu_selected_message)); }); m_menu_copy_id->show(); m_menu.append(*m_menu_copy_id); - m_menu_delete_message = Gtk::manage(new Gtk::MenuItem("Delete Message")); + m_menu_delete_message = Gtk::manage(new Gtk::MenuItem(_("Delete Message"))); m_menu_delete_message->signal_activate().connect([this] { Abaddon::Get().GetDiscordClient().DeleteMessage(m_active_channel, m_menu_selected_message); }); m_menu_delete_message->show(); m_menu.append(*m_menu_delete_message); - m_menu_edit_message = Gtk::manage(new Gtk::MenuItem("Edit Message")); + m_menu_edit_message = Gtk::manage(new Gtk::MenuItem(_("Edit Message"))); m_menu_edit_message->signal_activate().connect([this] { m_signal_action_message_edit.emit(m_active_channel, m_menu_selected_message); }); m_menu_edit_message->show(); m_menu.append(*m_menu_edit_message); - m_menu_copy_content = Gtk::manage(new Gtk::MenuItem("Copy Content")); + m_menu_copy_content = Gtk::manage(new Gtk::MenuItem(_("Copy Content"))); m_menu_copy_content->signal_activate().connect([this] { const auto msg = Abaddon::Get().GetDiscordClient().GetMessage(m_menu_selected_message); if (msg.has_value()) @@ -324,20 +325,20 @@ void ChatList::SetupMenu() { m_menu_copy_content->show(); m_menu.append(*m_menu_copy_content); - m_menu_reply_to = Gtk::manage(new Gtk::MenuItem("Reply To")); + m_menu_reply_to = Gtk::manage(new Gtk::MenuItem(_("Reply To"))); m_menu_reply_to->signal_activate().connect([this] { m_signal_action_reply_to.emit(m_menu_selected_message); }); m_menu_reply_to->show(); m_menu.append(*m_menu_reply_to); - m_menu_unpin = Gtk::manage(new Gtk::MenuItem("Unpin")); + m_menu_unpin = Gtk::manage(new Gtk::MenuItem(_("Unpin"))); m_menu_unpin->signal_activate().connect([this] { Abaddon::Get().GetDiscordClient().Unpin(m_active_channel, m_menu_selected_message, [](...) {}); }); m_menu.append(*m_menu_unpin); - m_menu_pin = Gtk::manage(new Gtk::MenuItem("Pin")); + m_menu_pin = Gtk::manage(new Gtk::MenuItem(_("Pin"))); m_menu_pin->signal_activate().connect([this] { Abaddon::Get().GetDiscordClient().Pin(m_active_channel, m_menu_selected_message, [](...) {}); }); diff --git a/src/components/chatmessage.cpp b/src/components/chatmessage.cpp index 8f2f5193..8f65abb9 100644 --- a/src/components/chatmessage.cpp +++ b/src/components/chatmessage.cpp @@ -1,5 +1,6 @@ #include "chatmessage.hpp" #include +#include #include #include "abaddon.hpp" #include "constants.hpp" @@ -11,7 +12,7 @@ ChatMessageItemContainer::ChatMessageItemContainer() : m_main(Gtk::ORIENTATION_VERTICAL) { add(m_main); - m_link_menu_copy = Gtk::manage(new Gtk::MenuItem("Copy Link")); + m_link_menu_copy = Gtk::manage(new Gtk::MenuItem(_("Copy Link"))); m_link_menu_copy->signal_activate().connect(sigc::mem_fun(*this, &ChatMessageItemContainer::on_link_menu_copy)); m_link_menu.append(*m_link_menu_copy); @@ -142,9 +143,9 @@ void ChatMessageItemContainer::UpdateAttributes() { } if (deleted) - m_attrib_label->set_markup("[deleted]"); + m_attrib_label->set_markup("[" + std::string { _("deleted") } + "]"); else if (edited) - m_attrib_label->set_markup("[edited]"); + m_attrib_label->set_markup("[" + std::string { _("edited") } + "]"); } void ChatMessageItemContainer::AddClickHandler(Gtk::Widget *widget, const std::string &url) { @@ -198,13 +199,13 @@ void ChatMessageItemContainer::UpdateTextComponent(Gtk::TextView *tv) { ChatUtil::HandleEmojis(*tv); break; case MessageType::USER_PREMIUM_GUILD_SUBSCRIPTION: - b->insert_markup(s, "[boosted server]"); + b->insert_markup(s, "[" + std::string { _("boosted server") } + "]"); break; case MessageType::GUILD_MEMBER_JOIN: - b->insert_markup(s, "[user joined]"); + b->insert_markup(s, "[" + std::string { _("user joined") } + "]"); break; case MessageType::CHANNEL_PINNED_MESSAGE: - b->insert_markup(s, "[message pinned]"); + b->insert_markup(s, "[" + std::string { _("message pinned") } + "]"); break; case MessageType::APPLICATION_COMMAND: { if (data->Application.has_value()) { @@ -214,7 +215,8 @@ void ChatMessageItemContainer::UpdateTextComponent(Gtk::TextView *tv) { if (regex->match(string, match)) { const auto cmd = match.fetch(1); const auto app = data->Application->Name; - b->insert_markup(s, "used " + cmd + " with " + app + ""); + auto app_command_text = Glib::ustring::compose(_("used %1 with %2"), cmd, app); + b->insert_markup(s, app_command_text); } } else { b->insert(s, data->Content); @@ -226,64 +228,85 @@ void ChatMessageItemContainer::UpdateTextComponent(Gtk::TextView *tv) { } break; case MessageType::RECIPIENT_ADD: { if (data->Mentions.empty()) break; - const auto &adder = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID); - const auto &added = data->Mentions[0]; - b->insert_markup(s, "" + adder->GetUsername() + " added " + added.GetUsername() + ""); + const auto &adder_username = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID)->GetUsername(); + const auto &added_username = data->Mentions[0].GetUsername(); + auto recipient_add_text = Glib::ustring::compose(_("%1 added %2"), adder_username, added_username); + b->insert_markup(s, recipient_add_text); } break; case MessageType::RECIPIENT_REMOVE: { if (data->Mentions.empty()) break; + const auto &adder = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID); const auto &added = data->Mentions[0]; - if (adder->ID == added.ID) - b->insert_markup(s, "" + adder->GetUsername() + " left"); - else - b->insert_markup(s, "" + adder->GetUsername() + " removed " + added.GetUsername() + ""); + Glib::ustring recipient_remove; + if (adder->ID == added.ID) { + recipient_remove = Glib::ustring::compose(_("%1 left"), adder->GetUsername()); + } else { + recipient_remove = Glib::ustring::compose(_("%1 removed %2"), + adder->GetUsername(), added.GetUsername()); + } + b->insert_markup(s, recipient_remove); } break; case MessageType::CHANNEL_NAME_CHANGE: { const auto author = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID); - b->insert_markup(s, "" + author->GetDisplayNameEscapedBold() + " changed the name to " + Glib::Markup::escape_text(data->Content) + ""); + auto channel_name_change_text = Glib::ustring::compose(_("%1 changed the name to %2"), author->GetDisplayNameEscapedBold(), Glib::Markup::escape_text(data->Content)); + b->insert_markup(s, channel_name_change_text); } break; case MessageType::CHANNEL_ICON_CHANGE: { const auto author = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID); - b->insert_markup(s, "" + author->GetDisplayNameEscapedBold() + " changed the channel icon"); + auto channel_icon_change_text = Glib::ustring::compose(_("%1 changed the channel icon"), author->GetDisplayNameEscapedBold()); + b->insert_markup(s, channel_icon_change_text); } break; case MessageType::USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1: case MessageType::USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2: case MessageType::USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3: { const auto author = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID); const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(*data->GuildID); - b->insert_markup(s, "" + author->GetDisplayNameEscapedBold() + " just boosted the server " + Glib::Markup::escape_text(data->Content) + " times! " + - Glib::Markup::escape_text(guild->Name) + " has achieved Level " + std::to_string(static_cast(data->Type) - 8) + "!"); // oo cheeky me !!! + auto user_premium_guild_subscription_text = Glib::ustring::compose(_("%1 just boosted the server %2 times! %3 has achieved Level %4!"), + author->GetDisplayNameEscapedBold(), + Glib::Markup::escape_text(data->Content), + Glib::Markup::escape_text(guild->Name), + (static_cast(data->Type) - 8)); + b->insert_markup(s, user_premium_guild_subscription_text); // oo cheeky me !!! } break; case MessageType::CHANNEL_FOLLOW_ADD: { const auto author = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID); - b->insert_markup(s, "" + author->GetDisplayNameEscapedBold() + " has added " + Glib::Markup::escape_text(data->Content) + " to this channel. Its most important updates will show up here."); + auto channel_follow_add_text = Glib::ustring::compose( + _("%1 has added %2 to this channel. Its most important updates will show up here."), + author->GetDisplayNameEscapedBold(), + Glib::Markup::escape_text(data->Content)); + b->insert_markup(s, channel_follow_add_text); } break; case MessageType::CALL: { - b->insert_markup(s, "[started a call]"); + b->insert_markup(s, "[" + std::string { _("started a call") } + "]"); } break; case MessageType::GUILD_DISCOVERY_DISQUALIFIED: { - b->insert_markup(s, "This server has been removed from Server Discovery because it no longer passes all the requirements."); + b->insert_markup(s, "" + std::string { _("This server has been removed from Server Discovery because it no longer passes all the requirements.") } + ""); } break; case MessageType::GUILD_DISCOVERY_REQUALIFIED: { - b->insert_markup(s, "This server is eligible for Server Discovery again and has been automatically relisted!"); + b->insert_markup(s, "" + std::string { _("This server is eligible for Server Discovery again and has been automatically relisted!") } + ""); } break; case MessageType::GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING: { - b->insert_markup(s, "This server has failed Discovery activity requirements for 1 week. If this server fails for 4 weeks in a row, it will be automatically removed from Discovery."); + b->insert_markup(s, "" + std::string { _("This server has failed Discovery activity requirements for 1 week. If this server fails for 4 weeks in a row, it will be automatically removed from Discovery.") } + ""); } break; case MessageType::GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING: { - b->insert_markup(s, "This server has failed Discovery activity requirements for 3 weeks in a row. If this server fails for 1 more week, it will be removed from Discovery."); + b->insert_markup(s, "" + std::string { _("This server has failed Discovery activity requirements for 3 weeks in a row. If this server fails for 1 more week, it will be removed from Discovery.") } + ""); } break; case MessageType::THREAD_CREATED: { const auto author = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID); + Glib::ustring thread_created_text; if (data->MessageReference.has_value() && data->MessageReference->ChannelID.has_value()) { - auto iter = b->insert_markup(s, "" + author->GetDisplayNameEscapedBold() + " started a thread: "); + thread_created_text = Glib::ustring::compose(_("%1 started a thread: "), author->GetDisplayNameEscapedBold()); + auto iter = b->insert_markup(s, thread_created_text); auto tag = b->create_tag(); tag->property_weight() = Pango::WEIGHT_BOLD; m_channel_tagmap[tag] = *data->MessageReference->ChannelID; b->insert_with_tag(iter, data->Content, tag); } else { - b->insert_markup(s, "" + author->GetDisplayNameEscapedBold() + " started a thread: " + Glib::Markup::escape_text(data->Content) + ""); + thread_created_text = Glib::ustring::compose(_("%1 started a thread: %2"), + author->GetDisplayNameEscapedBold(), + Glib::Markup::escape_text(data->Content)); + b->insert_markup(s, thread_created_text); } } break; default: break; @@ -687,7 +710,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateReplyComponent(const Message &data) return author->GetDisplayNameEscapedBold(guild_id); } - return "Unknown User"; + return Glib::ustring::compose("%1", _("Unknown User")); }; // if the message wasnt fetched from store it might have an un-fetched reference @@ -701,26 +724,28 @@ Gtk::Widget *ChatMessageItemContainer::CreateReplyComponent(const Message &data) if (data.Interaction.has_value()) { if (data.GuildID.has_value()) { - lbl->set_markup(get_author_markup(data.Interaction->User.ID, *data.GuildID) + - " used /" + - Glib::Markup::escape_text(data.Interaction->Name) + - ""); + auto interaction_user_from_guild_text = + Glib::ustring::compose( + _("%1 used /%2"), + get_author_markup(data.Interaction->User.ID, *data.GuildID), + Glib::Markup::escape_text(data.Interaction->Name)); + lbl->set_markup(interaction_user_from_guild_text); } else if (const auto user = discord.GetUser(data.Interaction->User.ID); user.has_value()) { lbl->set_markup(user->GetDisplayNameEscapedBold()); } else { - lbl->set_markup("Unknown User"); + lbl->set_markup(Glib::ustring::compose("%1", _("Unknown User"))); } } else if (referenced_message.has_value()) { if (referenced_message.value() == nullptr) { - lbl->set_markup("deleted message"); + lbl->set_markup(Glib::ustring::compose("%1", _("deleted message"))); } else { const auto &referenced = *referenced_message.value(); Glib::ustring text; if (referenced.Content.empty()) { if (!referenced.Attachments.empty()) { - text = "attachment"; + text = Glib::ustring::compose("%1", _("attachment")); } else if (!referenced.Embeds.empty()) { - text = "embed"; + text = Glib::ustring::compose("%1", _("embed")); } } else { auto buf = Gtk::TextBuffer::create(); @@ -740,7 +765,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateReplyComponent(const Message &data) } } } else { - lbl->set_markup("reply unavailable"); + lbl->set_markup(Glib::ustring::compose("%1", _("reply unavailable"))); } return box; diff --git a/src/components/chatwindow.cpp b/src/components/chatwindow.cpp index 6a44d84c..b6f94e4e 100644 --- a/src/components/chatwindow.cpp +++ b/src/components/chatwindow.cpp @@ -1,4 +1,7 @@ #include "chatwindow.hpp" + +#include + #include "abaddon.hpp" #include "chatinputindicator.hpp" #include "ratelimitindicator.hpp" @@ -327,9 +330,9 @@ void ChatWindow::StartReplying(Snowflake message_id) { m_is_replying = true; m_input->StartReplying(); if (author.has_value()) { - m_input_indicator->SetCustomMarkup("Replying to " + author->GetUsernameEscapedBold()); + m_input_indicator->SetCustomMarkup(Glib::ustring::format(_("Replying to %1"), author->GetUsernameEscapedBold())); } else { - m_input_indicator->SetCustomMarkup("Replying..."); + m_input_indicator->SetCustomMarkup(_("Replying...")); } } @@ -349,7 +352,7 @@ void ChatWindow::StartEditing(Snowflake message_id) { m_is_editing = true; m_editing_id = message_id; m_input->StartEditing(*message); - m_input_indicator->SetCustomMarkup("Editing..."); + m_input_indicator->SetCustomMarkup(_("Editing...")); } void ChatWindow::StopEditing() { diff --git a/src/components/friendslist.cpp b/src/components/friendslist.cpp index a1fab8db..8f1a8753 100644 --- a/src/components/friendslist.cpp +++ b/src/components/friendslist.cpp @@ -1,4 +1,6 @@ #include "friendslist.hpp" + +#include #include #include #include "abaddon.hpp" @@ -20,34 +22,37 @@ FriendsList::FriendsList() PopulateRelationships(); signal_map().connect(sigc::mem_fun(*this, &FriendsList::PopulateRelationships)); - constexpr static std::array strs = { - "Friends", - "Online", - "Pending", - "Blocked", + static std::array strs = { + _("Friends"), + _("Online"), + _("Pending"), + _("Blocked"), }; + // The counter assumes that strs won't be reordered whatsoever + int c = 0; for (const auto &x : strs) { auto *btn = Gtk::manage(new Gtk::RadioButton(m_group, x)); m_buttons.add(*btn); btn->show(); - btn->signal_toggled().connect([this, btn, str = x] { + btn->signal_toggled().connect([this, btn, c] { if (!btn->get_active()) return; - switch (str[0]) { // hehe - case 'F': + switch (c) { + case 0: m_filter_mode = FILTER_FRIENDS; break; - case 'O': + case 1: m_filter_mode = FILTER_ONLINE; break; - case 'P': + case 2: m_filter_mode = FILTER_PENDING; break; - case 'B': + case 3: m_filter_mode = FILTER_BLOCKED; break; } m_list.invalidate_filter(); }); + c++; } m_buttons.set_homogeneous(true); m_buttons.set_halign(Gtk::ALIGN_CENTER); @@ -106,7 +111,7 @@ void FriendsList::OnRelationshipRemove(Snowflake id, RelationshipType type) { void FriendsList::OnActionAccept(Snowflake id) { const auto cb = [this](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg(*dynamic_cast(get_toplevel()), "Failed to accept", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*dynamic_cast(get_toplevel()), _("Failed to accept"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -121,16 +126,16 @@ void FriendsList::OnActionRemove(Snowflake id) { Glib::ustring str; switch (*discord.GetRelationship(id)) { case RelationshipType::Blocked: - str = "Are you sure you want to unblock " + user->GetUsername() + "?"; + str = Glib::ustring::compose(_("Are you sure you want to unblock %1?"), user->GetUsername()); break; case RelationshipType::Friend: - str = "Are you sure you want to remove " + user->GetUsername() + "?"; + str = Glib::ustring::compose(_("Are you sure you want to remove %1?"), user->GetUsername()); break; case RelationshipType::PendingIncoming: - str = "Are you sure you want to ignore " + user->GetUsername() + "?"; + str = Glib::ustring::compose(_("Are you sure you want to ignore %1?"), user->GetUsername()); break; case RelationshipType::PendingOutgoing: - str = "Are you sure you want to cancel your request to " + user->GetUsername() + "?"; + str = Glib::ustring::compose(_("Are you sure you want to cancel your request to %1?"), user->GetUsername()); break; default: break; @@ -138,7 +143,7 @@ void FriendsList::OnActionRemove(Snowflake id) { if (Abaddon::Get().ShowConfirm(str, window)) { const auto cb = [window](DiscordError code) { if (code == DiscordError::NONE) return; - Gtk::MessageDialog dlg(*window, "Failed to remove user", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(*window, _("Failed to remove user"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); }; @@ -187,9 +192,9 @@ bool FriendsList::ListFilterFunc(Gtk::ListBoxRow *row_) { FriendsListAddComponent::FriendsListAddComponent() : Gtk::Box(Gtk::ORIENTATION_VERTICAL) - , m_label("Add a Friend", Gtk::ALIGN_START) + , m_label(_("Add a Friend"), Gtk::ALIGN_START) , m_status("", Gtk::ALIGN_START) - , m_add("Add") + , m_add(_("Add")) , m_box(Gtk::ORIENTATION_HORIZONTAL) { m_box.add(m_entry); m_box.add(m_add); @@ -199,7 +204,7 @@ FriendsListAddComponent::FriendsListAddComponent() m_label.set_halign(Gtk::ALIGN_CENTER); - m_entry.set_placeholder_text("Enter a Username#1234"); + m_entry.set_placeholder_text(_("Enter a Username#1234")); m_entry.signal_key_press_event().connect(sigc::mem_fun(*this, &FriendsListAddComponent::OnKeyPress), false); add(m_label); @@ -212,7 +217,7 @@ void FriendsListAddComponent::Submit() { if (m_requesting) return; auto text = m_entry.get_text(); - m_label.set_text("Invalid input"); // cheeky !! + m_label.set_text(_("Invalid input")); // cheeky !! m_entry.set_text(""); const auto hashpos = text.find("#"); if (hashpos == Glib::ustring::npos) return; @@ -222,14 +227,14 @@ void FriendsListAddComponent::Submit() { if (discriminator.find_first_not_of("0123456789") != Glib::ustring::npos) return; m_requesting = true; - m_label.set_text("Hang on..."); + m_label.set_text(_("Hang on...")); const auto cb = [this](DiscordError code) { m_requesting = false; if (code == DiscordError::NONE) { - m_label.set_text("Success!"); + m_label.set_text(_("Success!")); } else { - m_label.set_text("Failed: "s + GetDiscordErrorDisplayString(code)); + m_label.set_text(Glib::ustring::compose(_("Failed: %1"), GetDiscordErrorDisplayString(code))); } }; Abaddon::Get().GetDiscordClient().SendFriendRequest(username, @@ -250,7 +255,7 @@ FriendsListFriendRow::FriendsListFriendRow(RelationshipType type, const UserData , Type(type) , Name(data.GetUsername()) , Status(Abaddon::Get().GetDiscordClient().GetUserStatus(data.ID)) - , m_accept("Accept") { + , m_accept(_("Accept")) { auto *ev = Gtk::manage(new Gtk::EventBox); auto *box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); auto *img = Gtk::manage(new LazyImage(32, 32, true)); @@ -279,13 +284,13 @@ FriendsListFriendRow::FriendsListFriendRow(RelationshipType type, const UserData switch (Type) { case RelationshipType::Blocked: case RelationshipType::Friend: - m_remove.set_label("Remove"); + m_remove.set_label(_("Remove")); break; case RelationshipType::PendingIncoming: - m_remove.set_label("Ignore"); + m_remove.set_label(_("Ignore")); break; case RelationshipType::PendingOutgoing: - m_remove.set_label("Cancel"); + m_remove.set_label(_("Cancel")); break; default: break; @@ -323,10 +328,10 @@ FriendsListFriendRow::FriendsListFriendRow(RelationshipType type, const UserData void FriendsListFriendRow::UpdatePresenceLabel() { switch (Type) { case RelationshipType::PendingIncoming: - m_status_lbl->set_text("Incoming Friend Request"); + m_status_lbl->set_text(_("Incoming Friend Request")); break; case RelationshipType::PendingOutgoing: - m_status_lbl->set_text("Outgoing Friend Request"); + m_status_lbl->set_text(_("Outgoing Friend Request")); break; default: m_status_lbl->set_text(GetPresenceDisplayString(Status)); diff --git a/src/components/ratelimitindicator.cpp b/src/components/ratelimitindicator.cpp index 1eff3059..bb9a4a1a 100644 --- a/src/components/ratelimitindicator.cpp +++ b/src/components/ratelimitindicator.cpp @@ -2,6 +2,8 @@ #include +#include + #include "abaddon.hpp" #include "util.hpp" @@ -82,15 +84,15 @@ bool RateLimitIndicator::UpdateIndicator() { auto &discord = Abaddon::Get().GetDiscordClient(); if (discord.HasAnyChannelPermission(discord.GetUserData().ID, m_active_channel, Permission::MANAGE_MESSAGES | Permission::MANAGE_CHANNELS)) { - m_label.set_text("You may bypass slowmode."); + m_label.set_text(_("You may bypass slowmode.")); set_has_tooltip(false); } else { const auto time_left = GetTimeLeft(); if (time_left > 0) - m_label.set_text(std::to_string(time_left) + "s"); + m_label.set_text(Glib::ustring::compose(_("%1s"), std::to_string(time_left))); else m_label.set_text(""); - set_tooltip_text("Slowmode is enabled. Members can send one message every " + std::to_string(rate_limit) + " seconds."); + set_tooltip_text(Glib::ustring::compose(_("Slowmode is enabled. Members can send one message every %1 seconds"), std::to_string(rate_limit))); } } else { m_img.hide(); diff --git a/src/components/voiceinfobox.cpp b/src/components/voiceinfobox.cpp index b514cdca..057a56e4 100644 --- a/src/components/voiceinfobox.cpp +++ b/src/components/voiceinfobox.cpp @@ -2,6 +2,8 @@ // clang-format off +#include + #include "voiceinfobox.hpp" #include "abaddon.hpp" #include "util.hpp" @@ -28,8 +30,8 @@ VoiceInfoBox::VoiceInfoBox() m_location.get_style_context()->add_class("voice-info-location"); m_disconnect_img.get_style_context()->add_class("voice-info-disconnect-image"); - m_status.set_label("You shouldn't see me"); - m_location.set_label("You shouldn't see me"); + m_status.set_label(_("You shouldn't see me")); + m_location.set_label(_("You shouldn't see me")); Abaddon::Get().GetDiscordClient().signal_voice_requested_connect().connect([this](Snowflake channel_id) { show(); @@ -44,20 +46,20 @@ VoiceInfoBox::VoiceInfoBox() Glib::ustring label; switch (state) { case DiscordVoiceClient::State::ConnectingToWebsocket: - label = "Connecting"; + label = _("Connecting"); break; case DiscordVoiceClient::State::EstablishingConnection: - label = "Establishing connection"; + label = _("Establishing connection"); break; case DiscordVoiceClient::State::Connected: - label = "Connected"; + label = _("Connected"); break; case DiscordVoiceClient::State::DisconnectedByServer: case DiscordVoiceClient::State::DisconnectedByClient: - label = "Disconnected"; + label = _("Disconnected"); break; default: - label = "Unknown"; + label = _("Unknown"); break; } m_status.set_label(label); @@ -113,7 +115,7 @@ void VoiceInfoBox::UpdateLocation() { return; } - m_location.set_label("Unknown"); + m_location.set_label(_("Unknown")); } #endif diff --git a/src/dialogs/confirm.cpp b/src/dialogs/confirm.cpp index 8e606df9..84d7cb66 100644 --- a/src/dialogs/confirm.cpp +++ b/src/dialogs/confirm.cpp @@ -1,16 +1,18 @@ #include "confirm.hpp" +#include + ConfirmDialog::ConfirmDialog(Gtk::Window &parent) - : Gtk::Dialog("Confirm", parent, true) + : Gtk::Dialog(_("Confirm"), parent, true) , m_layout(Gtk::ORIENTATION_VERTICAL) , m_ok("OK") - , m_cancel("Cancel") + , m_cancel(_("Cancel")) , m_bbox(Gtk::ORIENTATION_HORIZONTAL) { set_default_size(300, 50); get_style_context()->add_class("app-window"); get_style_context()->add_class("app-popup"); - m_label.set_text("Are you sure?"); + m_label.set_text(_("Are you sure?")); m_ok.signal_clicked().connect([&]() { response(Gtk::RESPONSE_OK); diff --git a/src/dialogs/friendpicker.cpp b/src/dialogs/friendpicker.cpp index be597942..dba8fb9b 100644 --- a/src/dialogs/friendpicker.cpp +++ b/src/dialogs/friendpicker.cpp @@ -1,16 +1,18 @@ #include "friendpicker.hpp" +#include + #include "abaddon.hpp" FriendPickerDialog::FriendPickerDialog(Gtk::Window &parent) - : Gtk::Dialog("Pick a friend", parent, true) + : Gtk::Dialog(_("Pick a friend"), parent, true) , m_bbox(Gtk::ORIENTATION_HORIZONTAL) { set_default_size(300, 300); get_style_context()->add_class("app-window"); get_style_context()->add_class("app-popup"); m_ok_button = add_button("OK", Gtk::RESPONSE_OK); - m_cancel_button = add_button("Cancel", Gtk::RESPONSE_CANCEL); + m_cancel_button = add_button(_("Cancel"), Gtk::RESPONSE_CANCEL); m_ok_button->set_sensitive(false); diff --git a/src/dialogs/setstatus.cpp b/src/dialogs/setstatus.cpp index 8ca8ccff..2cb7f8bb 100644 --- a/src/dialogs/setstatus.cpp +++ b/src/dialogs/setstatus.cpp @@ -1,5 +1,7 @@ #include "setstatus.hpp" +#include + #include "abaddon.hpp" static const std::array feelings = { @@ -18,10 +20,10 @@ static const std::array feelings = { }; SetStatusDialog::SetStatusDialog(Gtk::Window &parent) - : Gtk::Dialog("Set Status", parent, true) + : Gtk::Dialog(_("Set Status"), parent, true) , m_layout(Gtk::ORIENTATION_VERTICAL) , m_ok("OK") - , m_cancel("Cancel") { + , m_cancel(_("Cancel")) { set_default_size(350, 200); get_style_context()->add_class("app-window"); get_style_context()->add_class("app-popup"); @@ -29,19 +31,19 @@ SetStatusDialog::SetStatusDialog(Gtk::Window &parent) m_text.set_placeholder_text("I feel " + Glib::ustring(feelings[rand() % feelings.size()]) + "!"); - m_status_combo.append("online", "Online"); - m_status_combo.append("dnd", "Do Not Disturb"); - m_status_combo.append("idle", "Away"); - m_status_combo.append("invisible", "Invisible"); - m_status_combo.set_active_text("Online"); + m_status_combo.append("online", _("Online")); + m_status_combo.append("dnd", _("Do Not Disturb")); + m_status_combo.append("idle", _("Away")); + m_status_combo.append("invisible", _("Invisible")); + m_status_combo.set_active_text(_("Online")); - m_type_combo.append("0", "Playing"); - m_type_combo.append("1", "Streaming"); - m_type_combo.append("2", "Listening to"); - m_type_combo.append("3", "Watching"); - m_type_combo.append("4", "Custom"); - m_type_combo.append("5", "Competing in"); - m_type_combo.set_active_text("Custom"); + m_type_combo.append("0", _("Playing")); + m_type_combo.append("1", _("Streaming")); + m_type_combo.append("2", _("Listening to")); + m_type_combo.append("3", _("Watching")); + m_type_combo.append("4", _("Custom")); + m_type_combo.append("5", _("Competing in")); + m_type_combo.set_active_text(_("Custom")); m_ok.signal_clicked().connect([this]() { response(Gtk::RESPONSE_OK); @@ -51,11 +53,11 @@ SetStatusDialog::SetStatusDialog(Gtk::Window &parent) response(Gtk::RESPONSE_CANCEL); }); - m_layout.pack_start(*Gtk::make_managed("How are you, " + Abaddon::Get().GetDiscordClient().GetUserData().GetDisplayName() + "?", Gtk::ALIGN_START)); + m_layout.pack_start(*Gtk::make_managed(Glib::ustring::compose(_("How are you, %1?"), Abaddon::Get().GetDiscordClient().GetUserData().GetDisplayName()), Gtk::ALIGN_START)); m_layout.pack_start(m_text); - m_layout.pack_start(*Gtk::make_managed("Status", Gtk::ALIGN_START)); + m_layout.pack_start(*Gtk::make_managed(_("Status"), Gtk::ALIGN_START)); m_layout.pack_start(m_status_combo); - m_layout.pack_start(*Gtk::make_managed("Activity", Gtk::ALIGN_START)); + m_layout.pack_start(*Gtk::make_managed(_("Activity"), Gtk::ALIGN_START)); m_layout.pack_start(m_type_combo); get_content_area()->add(m_layout); diff --git a/src/dialogs/textinput.cpp b/src/dialogs/textinput.cpp index ae75f708..ec6bb14d 100644 --- a/src/dialogs/textinput.cpp +++ b/src/dialogs/textinput.cpp @@ -1,5 +1,7 @@ #include "textinput.hpp" +#include + TextInputDialog::TextInputDialog(const Glib::ustring &prompt, const Glib::ustring &title, const Glib::ustring &placeholder, Gtk::Window &parent) : Gtk::Dialog(title, parent, true) , m_label(prompt) { @@ -7,7 +9,7 @@ TextInputDialog::TextInputDialog(const Glib::ustring &prompt, const Glib::ustrin get_style_context()->add_class("app-popup"); auto ok = add_button("OK", Gtk::RESPONSE_OK); - auto cancel = add_button("Cancel", Gtk::RESPONSE_CANCEL); + auto cancel = add_button(_("Cancel"), Gtk::RESPONSE_CANCEL); get_content_area()->add(m_label); get_content_area()->add(m_entry); diff --git a/src/dialogs/token.cpp b/src/dialogs/token.cpp index 32fb7858..f99e712a 100644 --- a/src/dialogs/token.cpp +++ b/src/dialogs/token.cpp @@ -1,5 +1,7 @@ #include "token.hpp" +#include + std::string trim(const std::string &str) { const auto first = str.find_first_not_of(' '); if (first == std::string::npos) return str; @@ -8,10 +10,10 @@ std::string trim(const std::string &str) { } TokenDialog::TokenDialog(Gtk::Window &parent) - : Gtk::Dialog("Set Token", parent, true) + : Gtk::Dialog(_("Set Token"), parent, true) , m_layout(Gtk::ORIENTATION_VERTICAL) , m_ok("OK") - , m_cancel("Cancel") + , m_cancel(_("Cancel")) , m_bbox(Gtk::ORIENTATION_HORIZONTAL) { set_default_size(300, 50); get_style_context()->add_class("app-window"); diff --git a/src/dialogs/verificationgate.cpp b/src/dialogs/verificationgate.cpp index 9c9bcf9d..a3b66bfe 100644 --- a/src/dialogs/verificationgate.cpp +++ b/src/dialogs/verificationgate.cpp @@ -1,15 +1,17 @@ #include "verificationgate.hpp" +#include + #include "abaddon.hpp" VerificationGateDialog::VerificationGateDialog(Gtk::Window &parent, Snowflake guild_id) - : Gtk::Dialog("Verification Required", parent, true) + : Gtk::Dialog(_("Verification Required"), parent, true) , m_bbox(Gtk::ORIENTATION_HORIZONTAL) { set_default_size(300, 300); get_style_context()->add_class("app-window"); get_style_context()->add_class("app-popup"); - m_ok_button = add_button("Accept", Gtk::RESPONSE_OK); + m_ok_button = add_button(_("Accept"), Gtk::RESPONSE_OK); m_scroll_rules.set_vexpand(true); m_scroll_rules.set_hexpand(true); diff --git a/src/discord/permissions.cpp b/src/discord/permissions.cpp index 63eeb9f7..30cb0a92 100644 --- a/src/discord/permissions.cpp +++ b/src/discord/permissions.cpp @@ -9,3 +9,213 @@ void from_json(const nlohmann::json &j, PermissionOverwrite &m) { JS_D("deny", tmp); m.Deny = static_cast(std::stoull(tmp)); } + +const char *GetPermissionString(Permission perm) { + switch (perm) { + case Permission::NONE: + return _("None"); + case Permission::CREATE_INSTANT_INVITE: + return _("Create Invite"); + case Permission::KICK_MEMBERS: + return _("Kick Members"); + case Permission::BAN_MEMBERS: + return _("Ban Members"); + case Permission::ADMINISTRATOR: + return _("Administrator"); + case Permission::MANAGE_CHANNELS: + return _("Manage Channels"); + case Permission::MANAGE_GUILD: + return _("Manage Server"); + case Permission::ADD_REACTIONS: + return _("Add Reactions"); + case Permission::VIEW_AUDIT_LOG: + return _("View Audit Log"); + case Permission::PRIORITY_SPEAKER: + return _("Use Priority Speaker"); + case Permission::STREAM: + return _("Video"); + case Permission::VIEW_CHANNEL: + return _("View Channels"); + case Permission::SEND_MESSAGES: + return _("Send Messages"); + case Permission::SEND_TTS_MESSAGES: + return _("Use TTS"); + case Permission::MANAGE_MESSAGES: + return _("Manage Messages"); + case Permission::EMBED_LINKS: + return _("Embed Links"); + case Permission::ATTACH_FILES: + return _("Attach Files"); + case Permission::READ_MESSAGE_HISTORY: + return _("Read Message History"); + case Permission::MENTION_EVERYONE: + return _("Mention @everyone"); + case Permission::USE_EXTERNAL_EMOJIS: + return _("Use External Emojis"); + case Permission::VIEW_GUILD_INSIGHTS: + return _("View Server Insights"); + case Permission::CONNECT: + return _("Connect to Voice"); + case Permission::SPEAK: + return _("Speak in Voice"); + case Permission::MUTE_MEMBERS: + return _("Mute Members"); + case Permission::DEAFEN_MEMBERS: + return _("Deafen Members"); + case Permission::MOVE_MEMBERS: + return _("Move Members"); + case Permission::USE_VAD: + return _("Use Voice Activation"); + case Permission::CHANGE_NICKNAME: + return _("Change Nickname"); + case Permission::MANAGE_NICKNAMES: + return _("Manage Nicknames"); + case Permission::MANAGE_ROLES: + return _("Manage Roles"); + case Permission::MANAGE_WEBHOOKS: + return _("Manage Webhooks"); + case Permission::MANAGE_GUILD_EXPRESSIONS: + return _("Manage Expressions"); + case Permission::USE_APPLICATION_COMMANDS: + return _("Use Application Commands"); + case Permission::MANAGE_EVENTS: + return _("Manage Events"); + case Permission::MANAGE_THREADS: + return _("Manage Threads"); + case Permission::CREATE_PUBLIC_THREADS: + return _("Create Public Threads"); + case Permission::CREATE_PRIVATE_THREADS: + return _("Create Private Threads"); + case Permission::USE_EXTERNAL_STICKERS: + return _("Use External Stickers"); + case Permission::SEND_MESSAGES_IN_THREADS: + return _("Send Messages In Threads"); + case Permission::USE_EMBEDDED_ACTIVITIES: + return _("Use Activities"); + case Permission::MODERATE_MEMBERS: + return _("Timeout Members"); + // case Permission::VIEW_CREATOR_MONETIZATION_ANALYTICS: + // return ""; + case Permission::USE_SOUNDBOARD: + return _("Use Soundboard"); + case Permission::CREATE_GUILD_EXPRESSIONS: + return _("Create Expressions"); + case Permission::CREATE_EVENTS: + return _("Create Events"); + case Permission::USE_EXTERNAL_SOUNDS: + return _("Use External Sounds"); + case Permission::SEND_VOICE_MESSAGES: + return _("Send Voice Messages"); + // case Permission::USE_CLYDE_AI: + // return ""; + case Permission::SET_VOICE_CHANNEL_STATUS: + return _("Set Voice Channel Status"); + default: + return _("Unknown Permission"); + } +} + +const char *GetPermissionDescription(Permission perm) { + switch (perm) { + case Permission::NONE: + return ""; + case Permission::CREATE_INSTANT_INVITE: + return _("Allows members to invite new people to this server."); + case Permission::KICK_MEMBERS: + return _("Allows members to remove other members from this server. Kicked members will be able to rejoin if they have another invite."); + case Permission::BAN_MEMBERS: + return _("Allows members to permanently ban other members from this server."); + case Permission::ADMINISTRATOR: + return _("Members with this permission will have every permission and will also bypass all channel specific permissions or restrictions (for example, these members would get access to all private channels). This is a dangerous permission to grant."); + case Permission::MANAGE_CHANNELS: + return _("Allows members to create, edit, or delete channels."); + case Permission::MANAGE_GUILD: + return _("Allows members to change this server's name, switch regions, and add bots to this server."); + case Permission::ADD_REACTIONS: + return _("Allows members to add new emoji reactions to a message. If this permission is disabled, members can still react using any existing reactions on a message."); + case Permission::VIEW_AUDIT_LOG: + return _("Allows members to view a record of who made which changes in this server."); + case Permission::PRIORITY_SPEAKER: + return _("Allows members to be more easily heard in voice channels. When activated, the volume of others without this permission will be automatically lowered. Priority Speaker is activated by using the Push to Talk (Priority) keybind."); + case Permission::STREAM: + return _("Allows members to share their video, screen share, or stream a game in this server."); + case Permission::VIEW_CHANNEL: + return _("Allows members to view channels by default (excluding private channels)."); + case Permission::SEND_MESSAGES: + return _("Allows members to send messages in text channels."); + case Permission::SEND_TTS_MESSAGES: + return _("Allows members to send text-to-speech messages by starting a message with /tts. These messages can be heard by anyone focused on this channel."); + case Permission::MANAGE_MESSAGES: + return _("Allows members to delete messages by other members or pin any message."); + case Permission::EMBED_LINKS: + return _("Allows links that members share to show embedded content in text channels."); + case Permission::ATTACH_FILES: + return _("Allows members to upload files or media in text channels."); + case Permission::READ_MESSAGE_HISTORY: + return _("Allows members to read previous messages sent in channels. If this permission is disabled, members only see messages sent when they are online and focused on that channel."); + case Permission::MENTION_EVERYONE: + return _("Allows members to use @everyone (everyone in the server) or @here (only online members in that channel). They can also @mention all roles, even if the role's \"Allow anyone to mention this role\" permission is disabled."); + case Permission::USE_EXTERNAL_EMOJIS: + return _("Allows members to use emoji from other servers, if they're a Discord Nitro member."); + case Permission::VIEW_GUILD_INSIGHTS: + return _("Allows members to view Server Insights, which shows data on community growth, engagement, and more."); + case Permission::CONNECT: + return _("Allows members to join voice channels and hear others."); + case Permission::SPEAK: + return _("Allows members to talk in voice channels. If this permission is disabled, members are default muted until somebody with the \"Mute Members\" permission unmutes them."); + case Permission::MUTE_MEMBERS: + return _("Allows members to mute other members in voice channels for everyone."); + case Permission::DEAFEN_MEMBERS: + return _("Allows members to deafen other members in voice channels, which means they won't be able to speak or hear others."); + case Permission::MOVE_MEMBERS: + return _("Allows members to move other members between voice channels that the member with the permission has access to."); + case Permission::USE_VAD: + return _("Allows members to speak in voice channels by simply talking. If this permission is disabled, members are required to use Push-to-talk. Good for controlling background noise or noisy members."); + case Permission::CHANGE_NICKNAME: + return _("Allows members to change their own nickname, a custom name for just this server."); + case Permission::MANAGE_NICKNAMES: + return _("Allows members to change the nicknames of other members."); + case Permission::MANAGE_ROLES: + return _("Allows members to create new roles and edit or delete roles lower than their highest role. Also allows members to change permissions of individual channels that they have access to."); + case Permission::MANAGE_WEBHOOKS: + return _("Allows members to create, edit, or delete webhooks, which can post messages from other apps or sites into this server."); + case Permission::MANAGE_GUILD_EXPRESSIONS: + return _("Allows members to add or remove custom emoji, stickers, and sounds in this server."); + case Permission::USE_APPLICATION_COMMANDS: + return _("Allows members to use commands from applications, including slash commands and context menu commands."); + case Permission::MANAGE_EVENTS: + return _("Allows members to edit and cancel events."); + case Permission::MANAGE_THREADS: + return _("Allows members to rename, delete, close, and turn on slow mode for threads. They can also view private threads."); + case Permission::CREATE_PUBLIC_THREADS: + return _("Allows members to create threads that everyone in a channel can view."); + case Permission::CREATE_PRIVATE_THREADS: + return _("Allows members to create invite-only threads."); + case Permission::USE_EXTERNAL_STICKERS: + return _("Allows members to use stickers from other servers, if they're a Discord Nitro member."); + case Permission::SEND_MESSAGES_IN_THREADS: + return _("Allows members to send messages in threads."); + case Permission::USE_EMBEDDED_ACTIVITIES: + return _("Allows members to use Activities in this server."); + case Permission::MODERATE_MEMBERS: + return _("When you put a user in timeout they will not be able to send messages in chat, reply within threads, react to messages, or speak in voice or Stage channels."); + // case Permission::VIEW_CREATOR_MONETIZATION_ANALYTICS: + // return ""; + case Permission::USE_SOUNDBOARD: + return _("Allows members to send sounds from server soundboard."); + case Permission::CREATE_GUILD_EXPRESSIONS: + return _("Allows members to add custom emoji, stickers, and sounds in this server."); + case Permission::CREATE_EVENTS: + return _("Allows members to create events."); + case Permission::USE_EXTERNAL_SOUNDS: + return _("Allows members to use sounds from other servers, if they're a Discord Nitro member."); + case Permission::SEND_VOICE_MESSAGES: + return _("Allows members to send voice messages."); + // case Permission::USE_CLYDE_AI: + // return ""; + case Permission::SET_VOICE_CHANNEL_STATUS: + return _("Allows members to create and edit voice channel status."); + default: + return ""; + } +} \ No newline at end of file diff --git a/src/discord/permissions.hpp b/src/discord/permissions.hpp index 0d2217f3..646857d9 100644 --- a/src/discord/permissions.hpp +++ b/src/discord/permissions.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include "json.hpp" #include "misc/bitwise.hpp" #include "snowflake.hpp" @@ -79,212 +80,6 @@ struct PermissionOverwrite { friend void from_json(const nlohmann::json &j, PermissionOverwrite &m); }; -constexpr const char *GetPermissionString(Permission perm) { - switch (perm) { - case Permission::NONE: - return "None"; - case Permission::CREATE_INSTANT_INVITE: - return "Create Invite"; - case Permission::KICK_MEMBERS: - return "Kick Members"; - case Permission::BAN_MEMBERS: - return "Ban Members"; - case Permission::ADMINISTRATOR: - return "Administrator"; - case Permission::MANAGE_CHANNELS: - return "Manage Channels"; - case Permission::MANAGE_GUILD: - return "Manage Server"; - case Permission::ADD_REACTIONS: - return "Add Reactions"; - case Permission::VIEW_AUDIT_LOG: - return "View Audit Log"; - case Permission::PRIORITY_SPEAKER: - return "Use Priority Speaker"; - case Permission::STREAM: - return "Video"; - case Permission::VIEW_CHANNEL: - return "View Channels"; - case Permission::SEND_MESSAGES: - return "Send Messages"; - case Permission::SEND_TTS_MESSAGES: - return "Use TTS"; - case Permission::MANAGE_MESSAGES: - return "Manage Messages"; - case Permission::EMBED_LINKS: - return "Embed Links"; - case Permission::ATTACH_FILES: - return "Attach Files"; - case Permission::READ_MESSAGE_HISTORY: - return "Read Message History"; - case Permission::MENTION_EVERYONE: - return "Mention @everyone"; - case Permission::USE_EXTERNAL_EMOJIS: - return "Use External Emojis"; - case Permission::VIEW_GUILD_INSIGHTS: - return "View Server Insights"; - case Permission::CONNECT: - return "Connect to Voice"; - case Permission::SPEAK: - return "Speak in Voice"; - case Permission::MUTE_MEMBERS: - return "Mute Members"; - case Permission::DEAFEN_MEMBERS: - return "Deafen Members"; - case Permission::MOVE_MEMBERS: - return "Move Members"; - case Permission::USE_VAD: - return "Use Voice Activation"; - case Permission::CHANGE_NICKNAME: - return "Change Nickname"; - case Permission::MANAGE_NICKNAMES: - return "Manage Nicknames"; - case Permission::MANAGE_ROLES: - return "Manage Roles"; - case Permission::MANAGE_WEBHOOKS: - return "Manage Webhooks"; - case Permission::MANAGE_GUILD_EXPRESSIONS: - return "Manage Expressions"; - case Permission::USE_APPLICATION_COMMANDS: - return "Use Application Commands"; - case Permission::MANAGE_EVENTS: - return "Manage Events"; - case Permission::MANAGE_THREADS: - return "Manage Threads"; - case Permission::CREATE_PUBLIC_THREADS: - return "Create Public Threads"; - case Permission::CREATE_PRIVATE_THREADS: - return "Create Private Threads"; - case Permission::USE_EXTERNAL_STICKERS: - return "Use External Stickers"; - case Permission::SEND_MESSAGES_IN_THREADS: - return "Send Messages In Threads"; - case Permission::USE_EMBEDDED_ACTIVITIES: - return "Use Activities"; - case Permission::MODERATE_MEMBERS: - return "Timeout Members"; - // case Permission::VIEW_CREATOR_MONETIZATION_ANALYTICS: - // return ""; - case Permission::USE_SOUNDBOARD: - return "Use Soundboard"; - case Permission::CREATE_GUILD_EXPRESSIONS: - return "Create Expressions"; - case Permission::CREATE_EVENTS: - return "Create Events"; - case Permission::USE_EXTERNAL_SOUNDS: - return "Use External Sounds"; - case Permission::SEND_VOICE_MESSAGES: - return "Send Voice Messages"; - // case Permission::USE_CLYDE_AI: - // return ""; - case Permission::SET_VOICE_CHANNEL_STATUS: - return "Set Voice Channel Status"; - default: - return "Unknown Permission"; - } -} +const char *GetPermissionString(Permission perm); -constexpr const char *GetPermissionDescription(Permission perm) { - switch (perm) { - case Permission::NONE: - return ""; - case Permission::CREATE_INSTANT_INVITE: - return "Allows members to invite new people to this server."; - case Permission::KICK_MEMBERS: - return "Allows members to remove other members from this server. Kicked members will be able to rejoin if they have another invite."; - case Permission::BAN_MEMBERS: - return "Allows members to permanently ban other members from this server."; - case Permission::ADMINISTRATOR: - return "Members with this permission will have every permission and will also bypass all channel specific permissions or restrictions (for example, these members would get access to all private channels). This is a dangerous permission to grant."; - case Permission::MANAGE_CHANNELS: - return "Allows members to create, edit, or delete channels."; - case Permission::MANAGE_GUILD: - return "Allows members to change this server's name, switch regions, and add bots to this server."; - case Permission::ADD_REACTIONS: - return "Allows members to add new emoji reactions to a message. If this permission is disabled, members can still react using any existing reactions on a message."; - case Permission::VIEW_AUDIT_LOG: - return "Allows members to view a record of who made which changes in this server."; - case Permission::PRIORITY_SPEAKER: - return "Allows members to be more easily heard in voice channels. When activated, the volume of others without this permission will be automatically lowered. Priority Speaker is activated by using the Push to Talk (Priority) keybind."; - case Permission::STREAM: - return "Allows members to share their video, screen share, or stream a game in this server."; - case Permission::VIEW_CHANNEL: - return "Allows members to view channels by default (excluding private channels)."; - case Permission::SEND_MESSAGES: - return "Allows members to send messages in text channels."; - case Permission::SEND_TTS_MESSAGES: - return "Allows members to send text-to-speech messages by starting a message with /tts. These messages can be heard by anyone focused on thsi channel."; - case Permission::MANAGE_MESSAGES: - return "Allows members to delete messages by other members or pin any message"; - case Permission::EMBED_LINKS: - return "Allows links that members share to show embedded content in text channels."; - case Permission::ATTACH_FILES: - return "Allows members to upload files or media in text channels."; - case Permission::READ_MESSAGE_HISTORY: - return "Allows members to read previous messages sent in channels. If this permission is disabled, members only see messages sent when they are online and focused on that channel."; - case Permission::MENTION_EVERYONE: - return "Allows members to use @everyone (everyone in the server) or @here (only online members in that channel). They can also @mention all roles, even if the role's \"Allow anyone to mention this role\" permission is disabled."; - case Permission::USE_EXTERNAL_EMOJIS: - return "Allows members to use emoji from other servers, if they're a Discord Nitro member"; - case Permission::VIEW_GUILD_INSIGHTS: - return "Allows members to view Server Insights, which shows data on community growth, engagement, and more."; - case Permission::CONNECT: - return "Allows members to join voice channels and hear others."; - case Permission::SPEAK: - return "Allows members to talk in voice channels. If this permission is disabled, members are default muted until somebody with the \"Mute Members\" permission un-mutes them."; - case Permission::MUTE_MEMBERS: - return "Allows members to mute other members in voice channels for everyone."; - case Permission::DEAFEN_MEMBERS: - return "Allows members to deafen other members in voice channels, which means they won't be able to speak or hear others."; - case Permission::MOVE_MEMBERS: - return "Allows members to move other members between voice channels that the member with the permission has access to."; - case Permission::USE_VAD: - return "Allows members to speak in voice channels by simply talking. If this permission is disabled, members are required to use Push-to-talk. Good for controlling background noise or noisy members."; - case Permission::CHANGE_NICKNAME: - return "Allows members to change their own nickname, a custom name for just this server."; - case Permission::MANAGE_NICKNAMES: - return "Allows members to change the nicknames of other members."; - case Permission::MANAGE_ROLES: - return "Allows members to create new roles and edit or delete roles lower than their highest role. Also allows members to change permissions of individual channels that they have access to."; - case Permission::MANAGE_WEBHOOKS: - return "Allows members to create, edit, or delete webhooks, which can post messages from other apps or sites into this server."; - case Permission::MANAGE_GUILD_EXPRESSIONS: - return "Allows members to add or remove custom emoji, stickers, and sounds in this server."; - case Permission::USE_APPLICATION_COMMANDS: - return "Allows members to use commands from applications, including slash commands and context menu commands."; - case Permission::MANAGE_EVENTS: - return "Allows members to edit and cancel events."; - case Permission::MANAGE_THREADS: - return "Allows members to rename, delete, close, and turn on slow mode for threads. They can also view private threads"; - case Permission::CREATE_PUBLIC_THREADS: - return "Allows members to create threads that everyone in a channel can view."; - case Permission::CREATE_PRIVATE_THREADS: - return "Allows members to create invite-only threads."; - case Permission::USE_EXTERNAL_STICKERS: - return "Allows members to use stickers from other servers, if they're a Discord Nitro member."; - case Permission::SEND_MESSAGES_IN_THREADS: - return "Allows members to send messages in threads."; - case Permission::USE_EMBEDDED_ACTIVITIES: - return "Allows members to use Activities in this server."; - case Permission::MODERATE_MEMBERS: - return "When you put a user in timeout they will not be able to send messages in chat, reply within threads, react to messages, or speak in voice or Stage channels."; - // case Permission::VIEW_CREATOR_MONETIZATION_ANALYTICS: - // return ""; - case Permission::USE_SOUNDBOARD: - return "Allows members to send sounds from server soundboard."; - case Permission::CREATE_GUILD_EXPRESSIONS: - return "Allows members to add custom emoji, stickers, and sounds in this server."; - case Permission::CREATE_EVENTS: - return "Allows members to create events."; - case Permission::USE_EXTERNAL_SOUNDS: - return "Allows members to use sounds from other servers, if they're a Discord Nitro member."; - case Permission::SEND_VOICE_MESSAGES: - return "Allows members to send voice messages."; - // case Permission::USE_CLYDE_AI: - // return ""; - case Permission::SET_VOICE_CHANNEL_STATUS: - return "Allows members to create and edit voice channel status."; - default: - return ""; - } -} +const char *GetPermissionDescription(Permission perm); diff --git a/src/discord/snowflake.hpp b/src/discord/snowflake.hpp index 68cb5ea0..2208f292 100644 --- a/src/discord/snowflake.hpp +++ b/src/discord/snowflake.hpp @@ -44,7 +44,7 @@ struct Snowflake { template<> struct fmt::formatter : fmt::formatter { - auto format(Snowflake id, format_context &ctx) -> decltype(ctx.out()) { + auto format(Snowflake id, format_context &ctx) const -> decltype(ctx.out()) { return format_to(ctx.out(), "[id: {}]", static_cast(id)); } }; diff --git a/src/platform.cpp b/src/platform.cpp index 726655be..ba450e8f 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -93,6 +93,10 @@ std::string Platform::FindStateCacheFolder() { return "."; } +std::string Platform::FindLocaleFolder() { + return "./locale/"; +} + #elif defined(__linux__) std::string Platform::FindResourceFolder() { static std::string found_path; @@ -160,6 +164,21 @@ std::string Platform::FindStateCacheFolder() { return "."; } +// !!! +std::string Platform::FindLocaleFolder() { + const auto home_env = std::getenv("HOME"); + if (home_env) { + if (std::filesystem::exists("/usr/share/locale/abaddon/")) { + return "/usr/share/locale/abaddon/"; + } else if (std::filesystem::exists(home_env + "/.local/share/abaddon/locale/"s)) { + return home_env + "/.local/share/abaddon/locale/"s; + } + } + + spdlog::get("discord")->warn("can't find locale folder!"); + return "./locale/"; +} + #elif defined(__APPLE__) #include #include @@ -224,6 +243,11 @@ std::string Platform::FindStateCacheFolder() { return home_path; } +std::string Platform::FindLocaleFolder() { + // TODO: Add thorough locale folder resolution code (Apple) + return "./locale/"; +} + #else std::string Platform::FindResourceFolder() { @@ -243,4 +267,9 @@ std::string Platform::FindStateCacheFolder() { spdlog::get("discord")->warn("unknown OS, setting state cache folder to cwd"); return "."; } + +std::string Platform::FindLocaleFolder() { + spdlog::get("discord")->warn("unknown OS, setting locale folder to cwd"); + return "./locale/"; +} #endif diff --git a/src/platform.hpp b/src/platform.hpp index 8083a5a2..be2351b8 100644 --- a/src/platform.hpp +++ b/src/platform.hpp @@ -6,4 +6,5 @@ bool SetupFonts(); std::string FindResourceFolder(); std::string FindConfigFile(); std::string FindStateCacheFolder(); +std::string FindLocaleFolder(); } // namespace Platform diff --git a/src/startup.cpp b/src/startup.cpp index 50b87447..0e7e31ec 100644 --- a/src/startup.cpp +++ b/src/startup.cpp @@ -1,5 +1,7 @@ #include "startup.hpp" +#include + #include #include @@ -9,7 +11,7 @@ DiscordStartupDialog::DiscordStartupDialog(Gtk::Window &window) : Gtk::MessageDialog(window, "", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE, true) { m_dispatcher.connect(sigc::mem_fun(*this, &DiscordStartupDialog::DispatchCallback)); - property_text() = "Getting connection info..."; + property_text() = _("Getting connection info..."); RunAsync(); } diff --git a/src/windows/guildsettings/auditlogpane.cpp b/src/windows/guildsettings/auditlogpane.cpp index 42e817eb..59fc0bde 100644 --- a/src/windows/guildsettings/auditlogpane.cpp +++ b/src/windows/guildsettings/auditlogpane.cpp @@ -1,5 +1,6 @@ #include "auditlogpane.hpp" +#include #include #include "abaddon.hpp" @@ -40,7 +41,7 @@ void GuildSettingsAuditLogPane::OnAuditLogFetch(const AuditLogData &data) { auto label = Gtk::manage(new Gtk::Label); label->set_ellipsize(Pango::ELLIPSIZE_END); - Glib::ustring user_markup = "Unknown User"; + Glib::ustring user_markup = Glib::ustring::compose("%1", _("Unknown User")); if (entry.UserID.has_value()) { if (auto user = discord.GetUser(*entry.UserID); user.has_value()) user_markup = discord.GetUser(*entry.UserID)->GetUsernameEscapedBold(); @@ -51,313 +52,278 @@ void GuildSettingsAuditLogPane::OnAuditLogFetch(const AuditLogData &data) { std::vector extra_markup; switch (entry.Type) { case AuditLogActionType::GUILD_UPDATE: { - markup = - user_markup + - " made changes to " + - Glib::Markup::escape_text(guild.Name) + - ""; + markup = Glib::ustring::compose(_("%1 made changes to %2"), + user_markup, Glib::Markup::escape_text(guild.Name)); if (entry.Changes.has_value()) for (const auto &change : *entry.Changes) { if (change.Key == "icon_hash") { - extra_markup.emplace_back("Set the server icon"); + extra_markup.emplace_back(_("Set the server icon")); } else if (change.Key == "name") { auto new_name = change.NewValue; if (new_name.has_value()) - extra_markup.push_back("Set the server name to " + - Glib::Markup::escape_text(new_name->get()) + - ""); + extra_markup.push_back( + Glib::ustring::compose(_("Set the server name to %1"), + Glib::Markup::escape_text(new_name->get()))); else - extra_markup.emplace_back("Set the server name"); + extra_markup.emplace_back(_("Set the server name")); } } } break; case AuditLogActionType::CHANNEL_CREATE: { const auto type = *entry.GetNewFromKey("type"); - markup = user_markup + - " created a " + (type == ChannelType::GUILD_VOICE ? "voice" : "text") + - " channel #" + - Glib::Markup::escape_text(*entry.GetNewFromKey("name")) + - ""; + if (type == ChannelType::GUILD_VOICE) { + markup = Glib::ustring::compose(_("%1 created a voice channel #%2"), + user_markup, Glib::Markup::escape_text(*entry.GetNewFromKey("name"))); + } else { + markup = Glib::ustring::compose(_("%1 created a text channel #%2"), + user_markup, Glib::Markup::escape_text(*entry.GetNewFromKey("name"))); + } + if (entry.Changes.has_value()) for (const auto &change : *entry.Changes) { if (change.Key == "name" && change.NewValue.has_value()) - extra_markup.push_back("Set the name to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); + extra_markup.push_back( + Glib::ustring::compose(_("Set the name to %1"), + Glib::Markup::escape_text(change.NewValue->get()))); else if (change.Key == "nsfw" && change.NewValue.has_value()) - extra_markup.emplace_back((*change.NewValue ? "Marked" : "Unmarked") + - " the channel as NSFW"s); + if (*change.NewValue) { + extra_markup.emplace_back(_("Marked the channel as NSFW")); + } else { + extra_markup.emplace_back(_("Unmarked the channel as NSFW")); + } } - } break; case AuditLogActionType::CHANNEL_UPDATE: { const auto target_channel = discord.GetChannel(entry.TargetID); if (target_channel.has_value()) { - markup = user_markup + - " made changes to #" + - Glib::Markup::escape_text(*target_channel->Name) + - ""; + markup = Glib::ustring::compose(_("%1 made changes to #%2"), + user_markup, Glib::Markup::escape_text(*target_channel->Name)); } else { - markup = user_markup + - " made changes to <#" + - entry.TargetID + - ">"; + markup = Glib::ustring::compose(_("%1 made changes to <#%2>"), + user_markup, Glib::Markup::escape_text(*target_channel->Name)); } + if (entry.Changes.has_value()) for (const auto &change : *entry.Changes) { if (change.Key == "name" && change.NewValue.has_value()) { - if (change.OldValue.has_value()) - extra_markup.push_back("Changed the name from " + - Glib::Markup::escape_text(change.OldValue->get()) + - " to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); - else - extra_markup.push_back("Changed the name to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); + if (change.OldValue.has_value()) { + auto old_name = Glib::Markup::escape_text(change.OldValue->get()); + auto new_name = Glib::Markup::escape_text(change.NewValue->get()); + extra_markup.push_back(Glib::ustring::compose(_("Changed the name from %1 to %2"), + old_name, new_name)); + } else { + auto new_name = Glib::Markup::escape_text(change.NewValue->get()); + extra_markup.push_back(Glib::ustring::compose(_("Changed the name to %1"), new_name)); + } } else if (change.Key == "topic") { - if (change.NewValue.has_value()) - extra_markup.push_back("Changed the topic to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); - else - extra_markup.emplace_back("Cleared the topic"); + if (change.NewValue.has_value()) { + auto new_topic = Glib::Markup::escape_text(change.NewValue->get()); + extra_markup.push_back(Glib::ustring::compose(_("Changed the topic to %1"), new_topic)); + } else { + extra_markup.emplace_back(_("Cleared the topic")); + } } else if (change.Key == "nsfw" && change.NewValue.has_value()) { - extra_markup.emplace_back((*change.NewValue ? "Marked" : "Unmarked") + " the channel as NSFW"s); + if (*change.NewValue) { + extra_markup.emplace_back(_("Marked the channel as NSFW")); + } else { + extra_markup.emplace_back(_("Unmarked the channel as NSFW")); + } } else if (change.Key == "rate_limit_per_user" && change.NewValue.has_value()) { const int secs = change.NewValue->get(); if (secs == 0) - extra_markup.emplace_back("Disabled slowmode"); + extra_markup.emplace_back(_("Disabled slowmode")); else - extra_markup.emplace_back("Set slowmode to " + - std::to_string(secs) + " seconds"); + extra_markup.emplace_back(Glib::ustring::compose(_("Set slowmode to %1 seconds"), secs)); } } } break; case AuditLogActionType::CHANNEL_DELETE: { - markup = user_markup + - " removed #" + - Glib::Markup::escape_text(*entry.GetOldFromKey("name")) + - ""; + auto deleted_channel_name = Glib::Markup::escape_text(*entry.GetOldFromKey("name")); + markup = Glib::ustring::compose(_("%1 removed #%2"), user_markup, deleted_channel_name); } break; case AuditLogActionType::CHANNEL_OVERWRITE_CREATE: { const auto channel = discord.GetChannel(entry.TargetID); if (channel.has_value()) { - markup = user_markup + - " created channel overrides for #" + - Glib::Markup::escape_text(*channel->Name) + ""; + auto channel_name = Glib::Markup::escape_text(*channel->Name); + markup = Glib::ustring::compose(_("%1 created channel overrides for #%2"), user_markup, channel_name); } else { - markup = user_markup + - " created channel overrides for <#" + - entry.TargetID + ">"; + markup = Glib::ustring::compose(_("%1 created channel overrides for <#%2>"), user_markup, entry.TargetID); } } break; case AuditLogActionType::CHANNEL_OVERWRITE_UPDATE: { const auto channel = discord.GetChannel(entry.TargetID); if (channel.has_value()) { - markup = user_markup + - " updated channel overrides for #" + - Glib::Markup::escape_text(*channel->Name) + ""; + auto channel_name = Glib::Markup::escape_text(*channel->Name); + markup = Glib::ustring::compose(_("%1 updated channel overrides for #%2"), user_markup, channel_name); } else { - markup = user_markup + - " updated channel overrides for <#" + - entry.TargetID + ">"; + markup = Glib::ustring::compose(_("%1 updated channel overrides for <#%2>"), user_markup, entry.TargetID); } } break; case AuditLogActionType::CHANNEL_OVERWRITE_DELETE: { const auto channel = discord.GetChannel(entry.TargetID); if (channel.has_value()) { - markup = user_markup + - " removed channel overrides for #" + - Glib::Markup::escape_text(*channel->Name) + ""; + auto channel_name = Glib::Markup::escape_text(*channel->Name); + markup = Glib::ustring::compose(_("%1 removed channel overrides for #%2"), user_markup, channel_name); } else { - markup = user_markup + - " removed channel overrides for <#" + - entry.TargetID + ">"; + markup = Glib::ustring::compose(_("%1 removed channel overrides for <#%2>"), user_markup, entry.TargetID); } } break; case AuditLogActionType::MEMBER_KICK: { - const auto target_user = discord.GetUser(entry.TargetID); - markup = user_markup + - " kicked " + - target_user->GetUsernameEscaped() + - ""; + const auto target_user = discord.GetUser(entry.TargetID)->GetUsernameEscaped(); + markup = Glib::ustring::compose(_("%1 kicked %2"), user_markup, target_user); } break; case AuditLogActionType::MEMBER_PRUNE: { - markup = user_markup + - " pruned " + - *entry.Options->MembersRemoved + - " members"; - extra_markup.emplace_back("For " + - *entry.Options->DeleteMemberDays + - " days of inactivity"); + markup = Glib::ustring::compose(_("%1 pruned %2 members"), user_markup, *entry.Options->MembersRemoved); + extra_markup.emplace_back(Glib::ustring::compose(_("For %1 days of inactivity"), *entry.Options->DeleteMemberDays)); } break; case AuditLogActionType::MEMBER_BAN_ADD: { - const auto target_user = discord.GetUser(entry.TargetID); - markup = user_markup + - " banned " + - target_user->GetUsernameEscaped() + - ""; + const auto target_user = discord.GetUser(entry.TargetID)->GetUsernameEscaped(); + markup = Glib::ustring::compose(_("%1 banned %2"), user_markup, target_user); } break; case AuditLogActionType::MEMBER_BAN_REMOVE: { - const auto target_user = discord.GetUser(entry.TargetID); - markup = user_markup + - " removed the ban for " + - target_user->GetUsernameEscaped() + - ""; + const auto target_user = discord.GetUser(entry.TargetID)->GetUsernameEscaped(); + markup = Glib::ustring::compose(_("%1 removed the ban for %2"), user_markup, target_user); } break; case AuditLogActionType::MEMBER_UPDATE: { - const auto target_user = discord.GetUser(entry.TargetID); - markup = user_markup + - " updated " + - target_user->GetUsernameEscaped() + - ""; - if (entry.Changes.has_value()) + const auto target_user = discord.GetUser(entry.TargetID)->GetUsername(); + markup = Glib::ustring::compose(_("%1 updated %2"), user_markup, target_user); + + if (entry.Changes.has_value()) { for (const auto &change : *entry.Changes) { if (change.Key == "deaf" && change.NewValue.has_value()) - extra_markup.emplace_back((change.NewValue->get() ? "Deafened"s : "Undeafened"s) + - " them"); + extra_markup.emplace_back(change.NewValue->get() ? _("Deafened them") : _("Undeafened them")); else if (change.Key == "mute" && change.NewValue.has_value()) - extra_markup.emplace_back((change.NewValue->get() ? "Muted"s : "Unmuted"s) + - " them"); + extra_markup.emplace_back(change.NewValue->get() ? _("Muted them") : _("Unmuted them")); else if (change.Key == "nick" && change.NewValue.has_value()) - extra_markup.push_back("Set their nickname to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); + extra_markup.push_back(Glib::ustring::compose(_("Set their nickname to %1"), Glib::Markup::escape_text(change.NewValue->get()))); } + } } break; case AuditLogActionType::MEMBER_ROLE_UPDATE: { - const auto target_user = discord.GetUser(entry.TargetID); - markup = user_markup + - " updated roles for " + - target_user->GetUsernameEscaped() + ""; - if (entry.Changes.has_value()) + const auto target_user = discord.GetUser(entry.TargetID)->GetUsernameEscaped(); + markup = Glib::ustring::compose(_("%1 updated roles for %2"), user_markup, target_user); + if (entry.Changes.has_value()) { for (const auto &change : *entry.Changes) { + auto role_name = Glib::Markup::escape_text(change.NewValue.value()[0].at("name").get()); if (change.Key == "$remove" && change.NewValue.has_value()) { - extra_markup.push_back("Removed a role " + - Glib::Markup::escape_text(change.NewValue.value()[0].at("name").get()) + - ""); + extra_markup.push_back(Glib::ustring::compose(_("Removed a role %1"), role_name)); } else if (change.Key == "$add" && change.NewValue.has_value()) { - extra_markup.push_back("Added a role " + - Glib::Markup::escape_text(change.NewValue.value()[0].at("name").get()) + - ""); + extra_markup.push_back(Glib::ustring::compose(_("Added a role %1"), role_name)); } } + } } break; + case AuditLogActionType::MEMBER_MOVE: { const auto channel = discord.GetChannel(*entry.Options->ChannelID); - markup = user_markup + - " moved " + - *entry.Options->Count + - " user" + - (*entry.Options->Count == "1" ? ""s : "s"s) + - " to " + - Glib::Markup::escape_text(*channel->Name) + - ""; + + if (*entry.Options->Count == "1") { + markup = Glib::ustring::compose(_("%1 moved a user to %2"), + user_markup, Glib::Markup::escape_text(*channel->Name)); + } else { + markup = Glib::ustring::compose(_("%1 moved %2 users to %3"), + user_markup, *entry.Options->Count, Glib::Markup::escape_text(*channel->Name)); + } } break; + case AuditLogActionType::MEMBER_DISCONNECT: { - markup = user_markup + - " disconnected " + - *entry.Options->Count + - " users from voice"; + markup = Glib::ustring::compose(_("%1 disconnected %2 users from voice"), + user_markup, *entry.Options->Count); } break; + case AuditLogActionType::BOT_ADD: { - const auto target_user = discord.GetUser(entry.TargetID); - markup = user_markup + - " added " + - target_user->GetUsernameEscaped() + - " to the server"; + const auto target_user = discord.GetUser(entry.TargetID)->GetUsernameEscaped(); + markup = Glib::ustring::compose(_("%1 added %2 to the server"), user_markup, target_user); } break; + case AuditLogActionType::ROLE_CREATE: { - markup = user_markup + - " created the role " + - *entry.GetNewFromKey("name") + - ""; + auto role_name = *entry.GetNewFromKey("name"); + markup = Glib::ustring::compose(_("%1 created the role %2"), user_markup, role_name); } break; + case AuditLogActionType::ROLE_UPDATE: { const auto role = discord.GetRole(entry.TargetID); - markup = user_markup + - " updated the role " + - (role.has_value() ? Glib::Markup::escape_text(role->Name) : Glib::ustring(entry.TargetID)) + - ""; - if (entry.Changes.has_value()) + markup = Glib::ustring::compose(_("%1 updated the role %2"), + user_markup, + (role.has_value() ? Glib::Markup::escape_text(role->Name) : Glib::ustring(entry.TargetID))); + if (entry.Changes.has_value()) { for (const auto &change : *entry.Changes) { if (change.Key == "name" && change.NewValue.has_value()) { - extra_markup.push_back("Changed the name to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); + auto new_name = Glib::Markup::escape_text(change.NewValue->get()); + extra_markup.push_back(Glib::ustring::compose(_("Changed the name to %1"), new_name)); } else if (change.Key == "color" && change.NewValue.has_value()) { const auto col = change.NewValue->get(); - if (col == 0) - extra_markup.emplace_back("Removed the color"); - else - extra_markup.emplace_back("Set the color to " + - IntToCSSColor(col) + - ""); + if (col == 0) { + extra_markup.emplace_back(_("Removed the color")); + } else { + extra_markup.emplace_back(Glib::ustring::compose(_("Set the color to %1"), IntToCSSColor(col))); + } } else if (change.Key == "permissions") { - extra_markup.emplace_back("Updated the permissions"); + extra_markup.emplace_back(_("Updated the permissions")); } else if (change.Key == "mentionable" && change.NewValue.has_value()) { - extra_markup.emplace_back(change.NewValue->get() ? "Mentionable" : "Not mentionable"); + extra_markup.emplace_back(change.NewValue->get() ? _("Mentionable") : _("Not mentionable")); } else if (change.Key == "hoist" && change.NewValue.has_value()) { - extra_markup.emplace_back(change.NewValue->get() ? "Not hoisted" : "Hoisted"); + extra_markup.emplace_back(change.NewValue->get() ? _("Not hoisted") : _("Hoisted")); } } + } } break; + case AuditLogActionType::ROLE_DELETE: { - markup = user_markup + - " deleted the role " + - *entry.GetOldFromKey("name") + - ""; + auto role_name = *entry.GetOldFromKey("name"); + markup = Glib::ustring::compose(_("%1 deleted the role %2"), user_markup, role_name); } break; + case AuditLogActionType::INVITE_CREATE: { - const auto code = *entry.GetNewFromKey("code"); - markup = user_markup + - " created an invite " + code + ""; - if (entry.Changes.has_value()) + auto code = *entry.GetNewFromKey("code"); + markup = Glib::ustring::compose(_("%1 created an invite %2"), user_markup, code); + if (entry.Changes.has_value()) { for (const auto &change : *entry.Changes) { if (change.Key == "channel_id" && change.NewValue.has_value()) { const auto channel = discord.GetChannel(change.NewValue->get()); - if (!channel.has_value()) continue; - extra_markup.push_back("For channel #" + - Glib::Markup::escape_text(*channel->Name) + - ""); + if (channel.has_value()) { + extra_markup.push_back(Glib::ustring::compose(_("For channel %1"), Glib::Markup::escape_text(*channel->Name))); + } } else if (change.Key == "max_uses" && change.NewValue.has_value()) { const auto uses = change.NewValue->get(); - if (uses == 0) - extra_markup.emplace_back("Which has unlimited uses"); - else - extra_markup.emplace_back("Which has " + std::to_string(uses) + " uses"); + if (uses == 0) { + extra_markup.emplace_back(_("Which has unlimited uses")); + } else { + extra_markup.emplace_back(Glib::ustring::compose(_("Which has %1 uses"), uses)); + } } else if (change.Key == "temporary" && change.NewValue.has_value()) { - extra_markup.emplace_back("With temporary "s + - (change.NewValue->get() ? "on" : "off") + - ""); - } // no max_age cuz fuck time + if (change.NewValue->get()) { + extra_markup.emplace_back(_("With temporary on")); + } else { + extra_markup.emplace_back(_("With temporary off")); + } + } } + } } break; + case AuditLogActionType::INVITE_DELETE: { - markup = user_markup + - " deleted an invite " + - *entry.GetOldFromKey("code") + - ""; + markup = Glib::ustring::compose(_("%1 deleted an invite %2"), user_markup, *entry.GetOldFromKey("code")); } break; + case AuditLogActionType::WEBHOOK_CREATE: { - markup = user_markup + - " created the webhook " + - Glib::Markup::escape_text(*entry.GetNewFromKey("name")) + - ""; + markup = Glib::ustring::compose( + _("%1 created the webhook %2"), + user_markup, + Glib::Markup::escape_text(*entry.GetNewFromKey("name"))); for (const auto &change : *entry.Changes) { if (change.Key == "channel_id" && change.NewValue.has_value()) { const auto channel = discord.GetChannel(change.NewValue->get()); if (channel.has_value()) { - extra_markup.push_back("With channel #" + - Glib::Markup::escape_text(*channel->Name) + - ""); + extra_markup.push_back(Glib::ustring::compose( + _("With channel #%1"), + Glib::Markup::escape_text(*channel->Name))); } } } } break; + case AuditLogActionType::WEBHOOK_UPDATE: { const WebhookData *webhookptr = nullptr; for (const auto &webhook : data.Webhooks) { @@ -365,248 +331,198 @@ void GuildSettingsAuditLogPane::OnAuditLogFetch(const AuditLogData &data) { webhookptr = &webhook; } if (webhookptr != nullptr) { - markup = user_markup + - " updated the webhook " + - Glib::Markup::escape_text(webhookptr->Name) + - ""; + markup = Glib::ustring::compose( + _("%1 updated the webhook %2"), + user_markup, + Glib::Markup::escape_text(webhookptr->Name)); } else { - markup = user_markup + - " updated a webhook"; + markup = Glib::ustring::compose( + _("%1 updated a webhook"), user_markup); } - if (entry.Changes.has_value()) + if (entry.Changes.has_value()) { for (const auto &change : *entry.Changes) { if (change.Key == "name" && change.NewValue.has_value()) { - extra_markup.push_back("Changed the name to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); + extra_markup.push_back(Glib::ustring::compose( + _("Changed the name to %1"), + Glib::Markup::escape_text(change.NewValue->get()))); } else if (change.Key == "avatar_hash") { - extra_markup.emplace_back("Changed the avatar"); + extra_markup.emplace_back(_("Changed the avatar")); } else if (change.Key == "channel_id" && change.NewValue.has_value()) { const auto channel = discord.GetChannel(change.NewValue->get()); if (channel.has_value()) { - extra_markup.push_back("Changed the channel to #" + - Glib::Markup::escape_text(*channel->Name) + - ""); + extra_markup.push_back(Glib::ustring::compose( + _("Changed the channel to #%1"), + Glib::Markup::escape_text(*channel->Name))); } else { - extra_markup.emplace_back("Changed the channel"); + extra_markup.emplace_back(_("Changed the channel")); } } } + } } break; + case AuditLogActionType::WEBHOOK_DELETE: { - markup = user_markup + - " deleted the webhook " + - Glib::Markup::escape_text(*entry.GetOldFromKey("name")) + - ""; + markup = Glib::ustring::compose( + _("%1 deleted the webhook %2"), + user_markup, + Glib::Markup::escape_text(*entry.GetOldFromKey("name"))); } break; + case AuditLogActionType::EMOJI_CREATE: { - markup = user_markup + - " created the emoji " + - Glib::Markup::escape_text(*entry.GetNewFromKey("name")) + - ""; + markup = Glib::ustring::compose( + _("%1 created the emoji %2"), + user_markup, + Glib::Markup::escape_text(*entry.GetNewFromKey("name"))); } break; + case AuditLogActionType::EMOJI_UPDATE: { - markup = user_markup + - " updated the emoji " + - Glib::Markup::escape_text(*entry.GetOldFromKey("name")) + - ""; - extra_markup.push_back("Changed the name from " + - Glib::Markup::escape_text(*entry.GetOldFromKey("name")) + - " to " + - Glib::Markup::escape_text(*entry.GetNewFromKey("name")) + - ""); + markup = Glib::ustring::compose( + _("%1 updated the emoji %2"), + user_markup, + Glib::Markup::escape_text(*entry.GetOldFromKey("name"))); + extra_markup.push_back(Glib::ustring::compose( + _("Changed the name from %1 to %2"), + Glib::Markup::escape_text(*entry.GetOldFromKey("name")), + Glib::Markup::escape_text(*entry.GetNewFromKey("name")))); } break; + case AuditLogActionType::EMOJI_DELETE: { - markup = user_markup + - " deleted the emoji " + - Glib::Markup::escape_text(*entry.GetOldFromKey("name")) + - ""; + markup = Glib::ustring::compose( + _("%1 deleted the emoji %2"), + user_markup, + Glib::Markup::escape_text(*entry.GetOldFromKey("name"))); } break; + + case AuditLogActionType::MESSAGE_BULK_DELETE: case AuditLogActionType::MESSAGE_DELETE: { const auto channel = discord.GetChannel(*entry.Options->ChannelID); const auto count = *entry.Options->Count; if (channel.has_value()) { - markup = user_markup + - " deleted " + count + " messages in #" + - Glib::Markup::escape_text(*channel->Name) + - ""; - } else { - markup = user_markup + - " deleted " + count + " messages"; - } - } break; - case AuditLogActionType::MESSAGE_BULK_DELETE: { - const auto channel = discord.GetChannel(entry.TargetID); - if (channel.has_value()) { - markup = user_markup + - " deleted " + - *entry.Options->Count + - " messages in #" + - Glib::Markup::escape_text(*channel->Name) + - ""; + markup = Glib::ustring::compose( + _("%1 deleted %2 messages in #%3"), + user_markup, count, Glib::Markup::escape_text(*channel->Name)); } else { - markup = user_markup + - " deleted " + - *entry.Options->Count + - " messages"; + markup = Glib::ustring::compose( + _("%1 deleted %2 messages"), + user_markup, count); } } break; + case AuditLogActionType::MESSAGE_PIN: { - const auto target_user = discord.GetUser(entry.TargetID); - markup = user_markup + - " pinned a message by " + - target_user->GetUsernameEscaped() + - ""; + const auto target_user = discord.GetUser(entry.TargetID)->GetUsernameEscaped(); + markup = Glib::ustring::compose( + _("%1 pinned a message by %2"), user_markup, target_user); } break; + case AuditLogActionType::MESSAGE_UNPIN: { - const auto target_user = discord.GetUser(entry.TargetID); - markup = user_markup + - " unpinned a message by " + - target_user->GetUsernameEscaped() + - ""; + const auto target_user = discord.GetUser(entry.TargetID)->GetUsernameEscaped(); + markup = Glib::ustring::compose( + _("%1 unpinned a message by %2"), user_markup, target_user); } break; + case AuditLogActionType::STAGE_INSTANCE_CREATE: { const auto channel = discord.GetChannel(*entry.Options->ChannelID); - if (channel.has_value()) { - markup = user_markup + - " started the stage for " + - Glib::Markup::escape_text(*channel->Name) + - ""; - } else { - markup = user_markup + - " started the stage for " + - std::to_string(*entry.Options->ChannelID) + - ""; - } + markup = Glib::ustring::compose(_("%1 started the stage for %2"), + user_markup, + (channel.has_value() ? Glib::Markup::escape_text(*channel->Name) : Glib::ustring { std::to_string(*entry.Options->ChannelID) })); if (entry.Changes.has_value()) { for (const auto &change : *entry.Changes) { if (change.Key == "topic" && change.NewValue.has_value()) { extra_markup.push_back( - "Set the topic to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); + Glib::ustring::compose(_("Set the topic to %1"), + Glib::Markup::escape_text(change.NewValue->get()))); } else if (change.Key == "privacy_level" && change.NewValue.has_value()) { Glib::ustring str = Glib::Markup::escape_text(GetStagePrivacyDisplayString(change.NewValue->get())); extra_markup.push_back( - "Set the privacy level to " + - str + - ""); + Glib::ustring::compose(_("Set the privacy level to %1"), str)); } } } } break; case AuditLogActionType::STAGE_INSTANCE_UPDATE: { const auto channel = discord.GetChannel(*entry.Options->ChannelID); - if (channel.has_value()) { - markup = user_markup + - " updated the stage for " + - Glib::Markup::escape_text(*channel->Name) + - ""; - } else { - markup = user_markup + - " updated the stage for " + - std::to_string(*entry.Options->ChannelID) + - ""; - } + markup = Glib::ustring::compose(_("%1 updated the stage for %2"), + user_markup, + (channel.has_value() ? Glib::Markup::escape_text(*channel->Name) : Glib::ustring { std::to_string(*entry.Options->ChannelID) })); if (entry.Changes.has_value()) { for (const auto &change : *entry.Changes) { if (change.Key == "topic" && change.NewValue.has_value()) { extra_markup.push_back( - "Set the topic to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); + Glib::ustring::compose(_("Set the topic to %1"), + Glib::Markup::escape_text(change.NewValue->get()))); } else if (change.Key == "privacy_level" && change.NewValue.has_value()) { Glib::ustring str = Glib::Markup::escape_text(GetStagePrivacyDisplayString(change.NewValue->get())); extra_markup.push_back( - "Set the privacy level to " + - str + - ""); + Glib::ustring::compose(_("Set the privacy level to %1"), str)); } } } } break; case AuditLogActionType::STAGE_INSTANCE_DELETE: { const auto channel = discord.GetChannel(*entry.Options->ChannelID); - if (channel.has_value()) { - markup = user_markup + - " ended the stage for " + - Glib::Markup::escape_text(*channel->Name) + - ""; - } else { - markup = user_markup + - " ended the stage for " + - std::to_string(*entry.Options->ChannelID) + - ""; - } + markup = Glib::ustring::compose(_("%1 ended the stage for %2"), + user_markup, + (channel.has_value() ? Glib::Markup::escape_text(*channel->Name) : Glib::ustring { std::to_string(*entry.Options->ChannelID) })); } break; case AuditLogActionType::THREAD_CREATE: { const auto channel = discord.GetChannel(entry.TargetID); - markup = user_markup + - " created a thread " + - (channel.has_value() - ? Glib::Markup::escape_text(*channel->Name) - : Glib::ustring(*entry.GetNewFromKey("name"))) + - ""; + markup = Glib::ustring::compose(_("%1 created a thread %2"), + user_markup.c_str(), + channel.has_value() ? Glib::Markup::escape_text(*channel->Name) : Glib::ustring(*entry.GetNewFromKey("name"))); if (entry.Changes.has_value()) { for (const auto &change : *entry.Changes) { if (change.Key == "name") - extra_markup.push_back("Set the name to " + Glib::Markup::escape_text(change.NewValue->get()) + ""); + extra_markup.push_back(Glib::ustring::compose(_("Set the name to %1"), + Glib::Markup::escape_text(change.NewValue->get()))); else if (change.Key == "archived") - extra_markup.emplace_back(change.NewValue->get() ? "Archived the thread" : "Unarchived the thread"); + extra_markup.emplace_back(change.NewValue->get() ? _("Archived the thread") : _("Unarchived the thread")); else if (change.Key == "auto_archive_duration") - extra_markup.emplace_back("Set auto archive duration to "s + std::to_string(change.NewValue->get()) + " minutes"s); + extra_markup.emplace_back(Glib::ustring::compose(_("Set auto archive duration to %1 minutes"), change.NewValue->get())); else if (change.Key == "rate_limit_per_user" && change.NewValue.has_value()) { const int secs = change.NewValue->get(); if (secs == 0) - extra_markup.emplace_back("Disabled slowmode"); + extra_markup.emplace_back(_("Disabled slowmode")); else - extra_markup.emplace_back("Set slowmode to " + - std::to_string(secs) + " seconds"); + extra_markup.emplace_back(Glib::ustring::compose(_("Set slowmode to %1 seconds"), secs)); } else if (change.Key == "locked") - extra_markup.emplace_back(change.NewValue->get() ? "Locked the thread, restricting it to only be unarchived by moderators" : "Unlocked the thread, allowing it to be unarchived by non-moderators"); + extra_markup.emplace_back(change.NewValue->get() ? _("Locked the thread, restricting it to only be unarchived by moderators") : _("Unlocked the thread, allowing it to be unarchived by non-moderators")); } } } break; case AuditLogActionType::THREAD_UPDATE: { const auto channel = discord.GetChannel(entry.TargetID); - markup = user_markup + - " made changes to the thread " + - (channel.has_value() - ? Glib::Markup::escape_text(*channel->Name) - : Glib::ustring(entry.TargetID)) + - ""; + markup = Glib::ustring::compose(_("%1 made changes to the thread %2"), + user_markup, + (channel.has_value() + ? Glib::Markup::escape_text(*channel->Name) + : Glib::ustring(entry.TargetID))); for (const auto &change : *entry.Changes) { if (change.Key == "name") - extra_markup.push_back( - "Changed the name from " + - Glib::Markup::escape_text(change.OldValue->get()) + - " to " + - Glib::Markup::escape_text(change.NewValue->get()) + - ""); + extra_markup.push_back(Glib::ustring::compose(_("Changed the name from %1 to %2"), + Glib::Markup::escape_text(change.OldValue->get()), + Glib::Markup::escape_text(change.NewValue->get()))); else if (change.Key == "auto_archive_duration") - extra_markup.emplace_back("Set auto archive duration to "s + std::to_string(change.NewValue->get()) + " minutes"s); + extra_markup.emplace_back(Glib::ustring::compose(_("Set auto archive duration to %1 minutes"), change.NewValue->get())); else if (change.Key == "rate_limit_per_user" && change.NewValue.has_value()) { const int secs = change.NewValue->get(); if (secs == 0) - extra_markup.emplace_back("Disabled slowmode"); + extra_markup.emplace_back(_("Disabled slowmode")); else - extra_markup.emplace_back("Set slowmode to " + - std::to_string(secs) + - " seconds"); + extra_markup.emplace_back(Glib::ustring::compose(_("Set slowmode to %1 seconds"), secs)); } else if (change.Key == "locked") - extra_markup.emplace_back(change.NewValue->get() ? "Locked the thread, restricting it to only be unarchived by moderators" : "Unlocked the thread, allowing it to be unarchived by non-moderators"); + extra_markup.emplace_back(change.NewValue->get() ? _("Locked the thread, restricting it to only be unarchived by moderators") : _("Unlocked the thread, allowing it to be unarchived by non-moderators")); else if (change.Key == "archived") - extra_markup.emplace_back(change.NewValue->get() ? "Archived the thread" : "Unarchived the thread"); + extra_markup.emplace_back(change.NewValue->get() ? _("Archived the thread") : _("Unarchived the thread")); } } break; case AuditLogActionType::THREAD_DELETE: { - markup = user_markup + - " deleted the thread " + Glib::Markup::escape_text(*entry.GetOldFromKey("name")) + ""; + markup = Glib::ustring::compose(_("%1 deleted the thread %2"), + user_markup, Glib::Markup::escape_text(*entry.GetOldFromKey("name"))); } break; default: - markup = "Unknown action"; + markup = Glib::ustring::compose("%1", _("Unknown action")); break; } @@ -614,9 +530,8 @@ void GuildSettingsAuditLogPane::OnAuditLogFetch(const AuditLogData &data) { expander->set_label_widget(*label); if (entry.Reason.has_value()) { - extra_markup.push_back("With reason " + - Glib::Markup::escape_text(*entry.Reason) + - ""); + extra_markup.push_back(Glib::ustring::compose(_("Reason: %1"), + Glib::Markup::escape_text(*entry.Reason))); } expander->set_expanded(true); diff --git a/src/windows/guildsettings/banspane.cpp b/src/windows/guildsettings/banspane.cpp index 550114d0..b3835c5c 100644 --- a/src/windows/guildsettings/banspane.cpp +++ b/src/windows/guildsettings/banspane.cpp @@ -1,5 +1,6 @@ #include "banspane.hpp" +#include #include #include "abaddon.hpp" @@ -8,8 +9,8 @@ GuildSettingsBansPane::GuildSettingsBansPane(Snowflake id) : Gtk::Box(Gtk::ORIENTATION_VERTICAL) , GuildID(id) , m_model(Gtk::ListStore::create(m_columns)) - , m_menu_unban("Unban") - , m_menu_copy_id("Copy ID") { + , m_menu_unban(_("Unban")) + , m_menu_copy_id(_("Copy ID")) { signal_map().connect(sigc::mem_fun(*this, &GuildSettingsBansPane::OnMap)); set_name("guild-bans-pane"); set_hexpand(true); @@ -27,7 +28,7 @@ GuildSettingsBansPane::GuildSettingsBansPane(Snowflake id) for (const auto &ban : discord.GetBansInGuild(id)) OnGuildBanFetch(ban); - m_no_perms_note = Gtk::manage(new Gtk::Label("You do not have permission to see bans. However, bans made while you are connected will appear here")); + m_no_perms_note = Gtk::manage(new Gtk::Label(_("You do not have permission to see bans. However, bans made while you are connected will appear here"))); m_no_perms_note->set_single_line_mode(true); m_no_perms_note->set_ellipsize(Pango::ELLIPSIZE_END); m_no_perms_note->set_halign(Gtk::ALIGN_START); @@ -51,8 +52,8 @@ GuildSettingsBansPane::GuildSettingsBansPane(Snowflake id) m_view.set_enable_search(false); m_view.set_model(m_model); - m_view.append_column("User", m_columns.m_col_user); - m_view.append_column("Reason", m_columns.m_col_reason); + m_view.append_column(_("User"), m_columns.m_col_user); + m_view.append_column(_("Reason"), m_columns.m_col_reason); } void GuildSettingsBansPane::OnMap() { @@ -96,7 +97,7 @@ void GuildSettingsBansPane::OnMenuUnban() { Snowflake id = selected_row[m_columns.m_col_id]; auto cb = [](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg("Failed to unban user", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("Failed to unban user"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } diff --git a/src/windows/guildsettings/emojispane.cpp b/src/windows/guildsettings/emojispane.cpp index 00f39ea5..e39293fc 100644 --- a/src/windows/guildsettings/emojispane.cpp +++ b/src/windows/guildsettings/emojispane.cpp @@ -1,5 +1,7 @@ #include "emojispane.hpp" +#include + #include #include @@ -12,10 +14,10 @@ GuildSettingsEmojisPane::GuildSettingsEmojisPane(Snowflake guild_id) , GuildID(guild_id) , m_model(Gtk::ListStore::create(m_columns)) , m_filter(Gtk::TreeModelFilter::create(m_model)) - , m_menu_delete("Delete") - , m_menu_copy_id("Copy ID") - , m_menu_copy_emoji_url("Copy Emoji URL") - , m_menu_show_emoji("Open in Browser") { + , m_menu_delete(_("Delete")) + , m_menu_copy_id(_("Copy ID")) + , m_menu_copy_emoji_url(_("Copy Emoji URL")) + , m_menu_show_emoji(_("Open in Browser")) { signal_map().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMap)); set_name("guild-emojis-pane"); @@ -43,7 +45,7 @@ GuildSettingsEmojisPane::GuildSettingsEmojisPane(Snowflake guild_id) const bool can_manage = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_GUILD_EXPRESSIONS); m_menu_delete.set_sensitive(can_manage); - m_search.set_placeholder_text("Filter"); + m_search.set_placeholder_text(_("Filter")); m_search.signal_changed().connect([this]() { m_filter->refilter(); }); @@ -63,7 +65,7 @@ GuildSettingsEmojisPane::GuildSettingsEmojisPane(Snowflake guild_id) m_view.set_enable_search(false); m_view.set_model(m_filter); - auto *column = Gtk::manage(new Gtk::TreeView::Column("Emoji")); + auto *column = Gtk::manage(new Gtk::TreeView::Column(_("Emoji"))); auto *renderer = Gtk::manage(new CellRendererPixbufAnimation); column->pack_start(*renderer); column->add_attribute(renderer->property_pixbuf(), m_columns.m_col_pixbuf); @@ -71,7 +73,7 @@ GuildSettingsEmojisPane::GuildSettingsEmojisPane(Snowflake guild_id) m_view.append_column(*column); if (can_manage) { - auto *column = Gtk::manage(new Gtk::TreeView::Column("Name")); + auto *column = Gtk::manage(new Gtk::TreeView::Column(_("Name"))); auto *renderer = Gtk::manage(new Gtk::CellRendererText); column->pack_start(*renderer); column->add_attribute(renderer->property_text(), m_columns.m_col_name); @@ -93,10 +95,10 @@ GuildSettingsEmojisPane::GuildSettingsEmojisPane(Snowflake guild_id) }); m_view.append_column(*column); } else - m_view.append_column("Name", m_columns.m_col_name); + m_view.append_column(_("Name"), m_columns.m_col_name); if (can_manage) - m_view.append_column("Creator", m_columns.m_col_creator); - m_view.append_column("Is Animated?", m_columns.m_col_animated); + m_view.append_column(_("Creator"), m_columns.m_col_creator); + m_view.append_column(_("Is Animated?"), m_columns.m_col_animated); for (const auto column : m_view.get_columns()) column->set_resizable(true); @@ -127,13 +129,13 @@ void GuildSettingsEmojisPane::AddEmojiRow(const EmojiData &emoji) { if (emoji.Creator.has_value()) row[m_columns.m_col_creator] = emoji.Creator->GetUsername(); if (emoji.IsAnimated.has_value()) - row[m_columns.m_col_animated] = *emoji.IsAnimated ? "Yes" : "No"; + row[m_columns.m_col_animated] = *emoji.IsAnimated ? _("Yes") : _("No"); else - row[m_columns.m_col_animated] = "No"; + row[m_columns.m_col_animated] = _("No"); if (emoji.IsAvailable.has_value()) - row[m_columns.m_col_available] = *emoji.IsAvailable ? "Yes" : "No"; + row[m_columns.m_col_available] = *emoji.IsAvailable ? _("Yes") : _("No"); else - row[m_columns.m_col_available] = "Yes"; + row[m_columns.m_col_available] = _("Yes"); if (Abaddon::Get().GetSettings().ShowAnimations && emoji.IsAnimated.has_value() && *emoji.IsAnimated) { const auto cb = [this, id = emoji.ID](const Glib::RefPtr &pb) { @@ -181,7 +183,7 @@ void GuildSettingsEmojisPane::OnFetchEmojis(std::vector emojis) { void GuildSettingsEmojisPane::OnEditName(Snowflake id, const std::string &name) { const auto cb = [](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg("Failed to set emoji name", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + Gtk::MessageDialog dlg(_("Failed to set emoji name"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -201,10 +203,10 @@ void GuildSettingsEmojisPane::OnMenuDelete() { const auto name = static_cast(selected_row[m_columns.m_col_name]); const auto id = static_cast(selected_row[m_columns.m_col_id]); if (auto *window = dynamic_cast(get_toplevel())) - if (Abaddon::Get().ShowConfirm("Are you sure you want to delete " + name + "?", window)) { + if (Abaddon::Get().ShowConfirm(Glib::ustring::compose(_("Are you sure you want to delete %1?"), name), window)) { const auto cb = [](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg("Failed to delete emoji", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + Gtk::MessageDialog dlg(_("Failed to delete emoji"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -217,7 +219,7 @@ void GuildSettingsEmojisPane::OnMenuDelete() { void GuildSettingsEmojisPane::OnMenuCopyEmojiURL() { if (auto selected_row = *m_view.get_selection()->get_selected()) { const auto id = static_cast(selected_row[m_columns.m_col_id]); - const bool is_animated = static_cast(selected_row[m_columns.m_col_animated]) == "Yes"; + const bool is_animated = static_cast(selected_row[m_columns.m_col_animated]) == _("Yes"); Gtk::Clipboard::get()->set_text(EmojiData::URLFromID(id, is_animated ? "gif" : "png", "256")); } } @@ -225,7 +227,7 @@ void GuildSettingsEmojisPane::OnMenuCopyEmojiURL() { void GuildSettingsEmojisPane::OnMenuShowEmoji() { if (auto selected_row = *m_view.get_selection()->get_selected()) { const auto id = static_cast(selected_row[m_columns.m_col_id]); - const bool is_animated = static_cast(selected_row[m_columns.m_col_animated]) == "Yes"; + const bool is_animated = static_cast(selected_row[m_columns.m_col_animated]) == _("Yes"); LaunchBrowser(EmojiData::URLFromID(id, is_animated ? "gif" : "png", "256")); } } diff --git a/src/windows/guildsettings/infopane.cpp b/src/windows/guildsettings/infopane.cpp index 45a87a40..10695b54 100644 --- a/src/windows/guildsettings/infopane.cpp +++ b/src/windows/guildsettings/infopane.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include #include @@ -10,7 +12,7 @@ #include "util.hpp" GuildSettingsInfoPane::GuildSettingsInfoPane(Snowflake id) - : m_guild_name_label("Guild name") + : m_guild_name_label(_("Guild name")) , GuildID(id) { auto &discord = Abaddon::Get().GetDiscordClient(); const auto guild = *discord.GetGuild(id); @@ -32,7 +34,7 @@ GuildSettingsInfoPane::GuildSettingsInfoPane(Snowflake id) // clang-format off }, false); // clang-format on - m_guild_name.set_tooltip_text("Press enter or lose focus to submit"); + m_guild_name.set_tooltip_text(_("Press enter or lose focus to submit")); m_guild_name.show(); m_guild_name_label.show(); @@ -48,7 +50,7 @@ GuildSettingsInfoPane::GuildSettingsInfoPane(Snowflake id) m_guild_icon.set_margin_bottom(10); if (can_modify) { - m_guild_icon_ev.set_tooltip_text("Click to choose a file, right click to paste"); + m_guild_icon_ev.set_tooltip_text(_("Click to choose a file, right click to paste")); m_guild_icon_ev.signal_button_press_event().connect([this](GdkEventButton *event) -> bool { if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) { @@ -104,7 +106,7 @@ void GuildSettingsInfoPane::UpdateGuildName() { auto cb = [this](DiscordError code) { if (code != DiscordError::NONE) { m_guild_name.set_text(Abaddon::Get().GetDiscordClient().GetGuild(GuildID)->Name); - Gtk::MessageDialog dlg("Failed to set guild name", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("Failed to set guild name"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -118,7 +120,7 @@ void GuildSettingsInfoPane::UpdateGuildIconFromData(const std::vector & auto cb = [](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg("Failed to set guild icon", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("Failed to set guild icon"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -142,7 +144,7 @@ void GuildSettingsInfoPane::UpdateGuildIconFromPixbuf(Glib::RefPtr } void GuildSettingsInfoPane::UpdateGuildIconPicker() { - auto dlg = Gtk::FileChooserNative::create("Choose new guild icon", Gtk::FILE_CHOOSER_ACTION_OPEN); + auto dlg = Gtk::FileChooserNative::create(_("Choose new guild icon"), Gtk::FILE_CHOOSER_ACTION_OPEN); dlg->set_modal(true); dlg->signal_response().connect([this, dlg](int response) { if (response == Gtk::RESPONSE_ACCEPT) { @@ -165,11 +167,12 @@ void GuildSettingsInfoPane::UpdateGuildIconPicker() { }); auto filter_images = Gtk::FileFilter::create(); + std::string supported_images_text = _("Supported images"); if (const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(GuildID); guild.has_value() && guild->HasFeature("ANIMATED_ICON")) { - filter_images->set_name("Supported images (*.jpg, *.jpeg, *.png, *.gif)"); + filter_images->set_name(supported_images_text + " (*.jpg, *.jpeg, *.png, *.gif)"); filter_images->add_pattern("*.gif"); } else { - filter_images->set_name("Supported images (*.jpg, *.jpeg, *.png)"); + filter_images->set_name(supported_images_text + " (*.jpg, *.jpeg, *.png)"); } filter_images->add_pattern("*.jpg"); filter_images->add_pattern("*.jpeg"); @@ -177,7 +180,7 @@ void GuildSettingsInfoPane::UpdateGuildIconPicker() { dlg->add_filter(filter_images); auto filter_all = Gtk::FileFilter::create(); - filter_all->set_name("All files (*.*)"); + filter_all->set_name(std::string{_("All files")} + " (*.*)"); filter_all->add_pattern("*.*"); dlg->add_filter(filter_all); diff --git a/src/windows/guildsettings/invitespane.cpp b/src/windows/guildsettings/invitespane.cpp index 157f9134..408f25b4 100644 --- a/src/windows/guildsettings/invitespane.cpp +++ b/src/windows/guildsettings/invitespane.cpp @@ -1,5 +1,6 @@ #include "invitespane.hpp" +#include #include #include "abaddon.hpp" @@ -8,7 +9,7 @@ GuildSettingsInvitesPane::GuildSettingsInvitesPane(Snowflake id) : GuildID(id) , m_model(Gtk::ListStore::create(m_columns)) - , m_menu_delete("Delete") { + , m_menu_delete(_("Delete")) { signal_map().connect(sigc::mem_fun(*this, &GuildSettingsInvitesPane::OnMap)); set_name("guild-invites-pane"); set_hexpand(true); @@ -30,12 +31,12 @@ GuildSettingsInvitesPane::GuildSettingsInvitesPane(Snowflake id) m_view.set_enable_search(false); m_view.set_model(m_model); - m_view.append_column("Code", m_columns.m_col_code); - m_view.append_column("Expires", m_columns.m_col_expires); - m_view.append_column("Created by", m_columns.m_col_inviter); - m_view.append_column("Uses", m_columns.m_col_uses); - m_view.append_column("Max uses", m_columns.m_col_max_uses); - m_view.append_column("Grants temporary membership", m_columns.m_col_temporary); + m_view.append_column(_("Code"), m_columns.m_col_code); + m_view.append_column(_("Expires"), m_columns.m_col_expires); + m_view.append_column(_("Created by"), m_columns.m_col_inviter); + m_view.append_column(_("Uses"), m_columns.m_col_uses); + m_view.append_column(_("Max uses"), m_columns.m_col_max_uses); + m_view.append_column(_("Grants temporary membership"), m_columns.m_col_temporary); for (const auto column : m_view.get_columns()) column->set_resizable(true); @@ -60,18 +61,18 @@ void GuildSettingsInvitesPane::AppendInvite(const InviteData &invite) { if (invite.MaxAge.has_value()) { if (*invite.MaxAge == 0) - row[m_columns.m_col_expires] = "Never"; + row[m_columns.m_col_expires] = _("Never"); else row[m_columns.m_col_expires] = FormatISO8601(*invite.CreatedAt, *invite.MaxAge); } row[m_columns.m_col_uses] = *invite.Uses; if (*invite.MaxUses == 0) - row[m_columns.m_col_max_uses] = "Unlimited"; + row[m_columns.m_col_max_uses] = _("Unlimited"); else row[m_columns.m_col_max_uses] = std::to_string(*invite.MaxUses); - row[m_columns.m_col_temporary] = *invite.IsTemporary ? "Yes" : "No"; + row[m_columns.m_col_temporary] = *invite.IsTemporary ? _("Yes") : _("No"); } void GuildSettingsInvitesPane::OnInviteFetch(const std::optional &invite) { @@ -102,7 +103,7 @@ void GuildSettingsInvitesPane::OnMenuDelete() { auto code = static_cast(selected_row[m_columns.m_col_code]); auto cb = [](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg("Failed to delete invite", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("Failed to delete invite"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } diff --git a/src/windows/guildsettings/memberspane.cpp b/src/windows/guildsettings/memberspane.cpp index a4acba1e..00712d6a 100644 --- a/src/windows/guildsettings/memberspane.cpp +++ b/src/windows/guildsettings/memberspane.cpp @@ -1,5 +1,7 @@ #include "memberspane.hpp" +#include + #include "abaddon.hpp" #include "util.hpp" @@ -15,7 +17,7 @@ GuildSettingsMembersPane::GuildSettingsMembersPane(Snowflake id) m_member_list.signal_member_select().connect(sigc::mem_fun(m_member_info, &GuildSettingsMembersPaneInfo::SetUser)); - m_note.set_label("Some members may not be shown if the client is not aware of them"); + m_note.set_label(_("Some members may not be shown if the client is not aware of them")); m_note.set_single_line_mode(true); m_note.set_ellipsize(Pango::ELLIPSIZE_END); @@ -59,7 +61,7 @@ GuildSettingsMembersPaneMembers::GuildSettingsMembersPaneMembers(Snowflake id) m_signal_member_select.emit(selected->UserID); }); - m_search.set_placeholder_text("Filter"); + m_search.set_placeholder_text(_("Filter")); m_search.signal_changed().connect([this] { m_list.invalidate_filter(); }); @@ -173,7 +175,7 @@ GuildSettingsMembersPaneInfo::GuildSettingsMembersPaneInfo(Snowflake guild_id) lbl.show(); }; - m_bot.set_text("User is a bot"); + m_bot.set_text(_("User is a bot")); label(m_bot); label(m_id); @@ -208,16 +210,16 @@ void GuildSettingsMembersPaneInfo::SetUser(Snowflake user_id) { m_bot.set_visible(member.User->IsABot()); - m_id.set_text("User ID: " + std::to_string(user_id)); - m_created.set_text("Account created: " + user_id.GetLocalTimestamp()); + m_id.set_text(_("User ID: ") + std::to_string(user_id)); + m_created.set_text(_("Account created: ") + user_id.GetLocalTimestamp()); if (!member.JoinedAt.empty()) - m_joined.set_text("Joined server: " + FormatISO8601(member.JoinedAt)); + m_joined.set_text(_("Joined server: ") + FormatISO8601(member.JoinedAt)); else - m_joined.set_text("Joined server: Unknown"); - m_nickname.set_text("Nickname: " + member.Nickname); + m_joined.set_text(_("Joined server: Unknown")); + m_nickname.set_text(_("Nickname: ") + member.Nickname); m_nickname.set_visible(!member.Nickname.empty()); if (member.PremiumSince.has_value()) { - m_boosting.set_text("Boosting since " + FormatISO8601(*member.PremiumSince)); + m_boosting.set_text(Glib::ustring::compose(_("Boosting since %1"), FormatISO8601(*member.PremiumSince))); m_boosting.show(); } else m_boosting.hide(); diff --git a/src/windows/guildsettings/rolespane.cpp b/src/windows/guildsettings/rolespane.cpp index fcb34bd6..193b9793 100644 --- a/src/windows/guildsettings/rolespane.cpp +++ b/src/windows/guildsettings/rolespane.cpp @@ -1,5 +1,6 @@ #include "rolespane.hpp" +#include #include #include "abaddon.hpp" @@ -67,7 +68,7 @@ GuildSettingsRolesPaneRoles::GuildSettingsRolesPaneRoles(Snowflake guild_id) if (!discord.CanModifyRole(GuildID, row->RoleID)) return false; const auto cb = [](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg("Failed to set role position", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("Failed to set role position"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER_ON_PARENT); dlg.run(); } @@ -114,7 +115,7 @@ GuildSettingsRolesPaneRoles::GuildSettingsRolesPaneRoles(Snowflake guild_id) return true; }); - m_search.set_placeholder_text("Filter"); + m_search.set_placeholder_text(_("Filter")); m_search.signal_changed().connect([this] { m_list.invalidate_filter(); }); @@ -213,7 +214,7 @@ GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id) }; m_role_name.signal_key_press_event().connect(cb, false); - m_role_name.set_tooltip_text("Press enter to submit"); + m_role_name.set_tooltip_text(_("Press enter to submit")); m_role_name.set_max_length(100); @@ -232,7 +233,7 @@ GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id) const auto cb = [this, &discord](DiscordError code) { if (code != DiscordError::NONE) { m_color_button.set_rgba(IntToRGBA(discord.GetRole(RoleID)->Color)); - Gtk::MessageDialog dlg("Failed to set role color", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("Failed to set role color"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER_ON_PARENT); dlg.run(); } @@ -263,7 +264,7 @@ GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id) // fuck you clang-format you suck // clang-format off - add_perms("General", RIGHT, { + add_perms(_("General"), RIGHT, { Permission::VIEW_CHANNEL, Permission::MANAGE_CHANNELS, Permission::MANAGE_ROLES, @@ -273,7 +274,7 @@ GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id) Permission::MANAGE_WEBHOOKS, Permission::MANAGE_GUILD }); - add_perms("Text Channels", LEFT, { + add_perms(_("Text Channels"), LEFT, { Permission::SEND_MESSAGES, Permission::SEND_MESSAGES_IN_THREADS, Permission::CREATE_PUBLIC_THREADS, @@ -291,7 +292,7 @@ GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id) Permission::USE_APPLICATION_COMMANDS, Permission::SEND_VOICE_MESSAGES, }); - add_perms("Membership", LEFT, { + add_perms(_("Membership"), LEFT, { Permission::CREATE_INSTANT_INVITE, Permission::CHANGE_NICKNAME, Permission::MANAGE_NICKNAMES, @@ -299,9 +300,9 @@ GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id) Permission::BAN_MEMBERS, Permission::MODERATE_MEMBERS }); - add_perms("Advanced", LEFT, { Permission::ADMINISTRATOR }); + add_perms(_("Advanced"), LEFT, { Permission::ADMINISTRATOR }); - add_perms("Voice Channels", RIGHT, { + add_perms(_("Voice Channels"), RIGHT, { Permission::CONNECT, Permission::SPEAK, Permission::STREAM, @@ -315,7 +316,7 @@ GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id) Permission::MOVE_MEMBERS, Permission::SET_VOICE_CHANNEL_STATUS }); - add_perms("Events", RIGHT, { + add_perms(_("Events"), RIGHT, { Permission::CREATE_EVENTS, Permission::MANAGE_EVENTS, }); @@ -408,7 +409,7 @@ void GuildSettingsRolesPaneInfo::UpdateRoleName() { const auto cb = [this, &discord](DiscordError code) { if (code != DiscordError::NONE) { m_role_name.set_text(discord.GetRole(RoleID)->Name); - Gtk::MessageDialog dlg("Failed to set role name", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("Failed to set role name"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER_ON_PARENT); dlg.run(); } diff --git a/src/windows/guildsettingswindow.cpp b/src/windows/guildsettingswindow.cpp index ce390e0f..9fdab566 100644 --- a/src/windows/guildsettingswindow.cpp +++ b/src/windows/guildsettingswindow.cpp @@ -1,5 +1,7 @@ #include "guildsettingswindow.hpp" +#include + #include "abaddon.hpp" GuildSettingsWindow::GuildSettingsWindow(Snowflake id) @@ -59,15 +61,15 @@ GuildSettingsWindow::GuildSettingsWindow(Snowflake id) const auto self_id = discord.GetUserData().ID; - m_stack.add(m_pane_info, "info", "Info"); - m_stack.add(m_pane_members, "members", "Members"); - m_stack.add(m_pane_roles, "roles", "Roles"); - m_stack.add(m_pane_bans, "bans", "Bans"); + m_stack.add(m_pane_info, "info", _("Info")); + m_stack.add(m_pane_members, "members", _("Members")); + m_stack.add(m_pane_roles, "roles", _("Roles")); + m_stack.add(m_pane_bans, "bans", _("Bans")); if (discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_GUILD)) - m_stack.add(m_pane_invites, "invites", "Invites"); - m_stack.add(m_pane_emojis, "emojis", "Emojis"); + m_stack.add(m_pane_invites, "invites", _("Invites")); + m_stack.add(m_pane_emojis, "emojis", _("Emojis")); if (discord.HasGuildPermission(self_id, GuildID, Permission::VIEW_AUDIT_LOG)) - m_stack.add(m_pane_audit_log, "audit-log", "Audit Log"); + m_stack.add(m_pane_audit_log, "audit-log", _("Audit Log")); m_stack.show(); m_main.add(m_switcher); diff --git a/src/windows/mainwindow.cpp b/src/windows/mainwindow.cpp index ee28d175..b7ea297b 100644 --- a/src/windows/mainwindow.cpp +++ b/src/windows/mainwindow.cpp @@ -1,5 +1,7 @@ #include "mainwindow.hpp" +#include + #include "abaddon.hpp" #include "util.hpp" @@ -253,19 +255,19 @@ MemberList *MainWindow::GetMemberList() { void MainWindow::SetupMenu() { m_menu_discord.set_label("Discord"); m_menu_discord.set_submenu(m_menu_discord_sub); - m_menu_discord_connect.set_label("Connect"); + m_menu_discord_connect.set_label(_("Connect")); m_menu_discord_connect.set_sensitive(false); - m_menu_discord_disconnect.set_label("Disconnect"); + m_menu_discord_disconnect.set_label(_("Disconnect")); m_menu_discord_disconnect.set_sensitive(false); - m_menu_discord_set_token.set_label("Set Token"); - m_menu_discord_login_qr.set_label("Login with QR Code"); + m_menu_discord_set_token.set_label(_("Set Token")); + m_menu_discord_login_qr.set_label(_("Login with QR Code")); #ifndef WITH_QRLOGIN m_menu_discord_login_qr.set_sensitive(false); - m_menu_discord_login_qr.set_tooltip_text("Not compiled with support"); + m_menu_discord_login_qr.set_tooltip_text(_("Not compiled with support")); #endif - m_menu_discord_set_status.set_label("Set Status"); + m_menu_discord_set_status.set_label(_("Set Status")); m_menu_discord_set_status.set_sensitive(false); - m_menu_discord_add_recipient.set_label("Add user to DM"); + m_menu_discord_add_recipient.set_label(_("Add user to DM")); m_menu_discord_sub.append(m_menu_discord_connect); m_menu_discord_sub.append(m_menu_discord_disconnect); m_menu_discord_sub.append(m_menu_discord_set_token); @@ -274,31 +276,31 @@ void MainWindow::SetupMenu() { m_menu_discord_sub.append(m_menu_discord_add_recipient); m_menu_discord.set_submenu(m_menu_discord_sub); - m_menu_file.set_label("File"); + m_menu_file.set_label(_("File")); m_menu_file.set_submenu(m_menu_file_sub); - m_menu_file_reload_css.set_label("Reload CSS"); - m_menu_file_clear_cache.set_label("Clear file cache"); - m_menu_file_dump_ready.set_label("Dump ready message"); + m_menu_file_reload_css.set_label(_("Reload CSS")); + m_menu_file_clear_cache.set_label(_("Clear file cache")); + m_menu_file_dump_ready.set_label(_("Dump ready message")); m_menu_file_sub.append(m_menu_file_reload_css); m_menu_file_sub.append(m_menu_file_clear_cache); m_menu_file_sub.append(m_menu_file_dump_ready); - m_menu_view.set_label("View"); + m_menu_view.set_label(_("View")); m_menu_view.set_submenu(m_menu_view_sub); - m_menu_view_friends.set_label("Friends"); - m_menu_view_pins.set_label("Pins"); - m_menu_view_threads.set_label("Threads"); - m_menu_view_mark_guild_as_read.set_label("Mark Server as Read"); + m_menu_view_friends.set_label(_("Friends")); + m_menu_view_pins.set_label(_("Pins")); + m_menu_view_threads.set_label(_("Threads")); + m_menu_view_mark_guild_as_read.set_label(_("Mark Server as Read")); m_menu_view_mark_guild_as_read.add_accelerator("activate", m_accels, GDK_KEY_Escape, Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); - m_menu_view_channels.set_label("Channels"); + m_menu_view_channels.set_label(_("Channels")); m_menu_view_channels.add_accelerator("activate", m_accels, GDK_KEY_L, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); m_menu_view_channels.set_active(true); - m_menu_view_members.set_label("Members"); + m_menu_view_members.set_label(_("Members")); m_menu_view_members.add_accelerator("activate", m_accels, GDK_KEY_M, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); m_menu_view_members.set_active(true); #ifdef WITH_LIBHANDY - m_menu_view_go_back.set_label("Go Back"); - m_menu_view_go_forward.set_label("Go Forward"); + m_menu_view_go_back.set_label(_("Go Back")); + m_menu_view_go_forward.set_label(_("Go Forward")); m_menu_view_go_back.add_accelerator("activate", m_accels, GDK_KEY_Left, Gdk::MOD1_MASK, Gtk::ACCEL_VISIBLE); m_menu_view_go_forward.add_accelerator("activate", m_accels, GDK_KEY_Right, Gdk::MOD1_MASK, Gtk::ACCEL_VISIBLE); #endif diff --git a/src/windows/pinnedwindow.cpp b/src/windows/pinnedwindow.cpp index 05435cbc..eb81dbcf 100644 --- a/src/windows/pinnedwindow.cpp +++ b/src/windows/pinnedwindow.cpp @@ -1,5 +1,7 @@ #include "pinnedwindow.hpp" +#include + #include "abaddon.hpp" PinnedWindow::PinnedWindow(const ChannelData &data) @@ -10,9 +12,9 @@ PinnedWindow::PinnedWindow(const ChannelData &data) set_name("pinned-messages"); set_default_size(450, 375); if (data.Name.has_value()) - set_title("#" + *data.Name + " - Pinned Messages"); + set_title(Glib::ustring::compose(_("#%1 - Pinned Messages"), *data.Name)); else - set_title("Pinned Messages"); + set_title(_("Pinned Messages")); set_position(Gtk::WIN_POS_CENTER); get_style_context()->add_class("app-window"); get_style_context()->add_class("app-popup"); diff --git a/src/windows/profile/mutualguildspane.cpp b/src/windows/profile/mutualguildspane.cpp index 86d66193..ad40a522 100644 --- a/src/windows/profile/mutualguildspane.cpp +++ b/src/windows/profile/mutualguildspane.cpp @@ -1,5 +1,7 @@ #include "mutualguildspane.hpp" +#include + #include "abaddon.hpp" MutualGuildItem::MutualGuildItem(const MutualGuildData &guild) @@ -33,7 +35,7 @@ MutualGuildItem::MutualGuildItem(const MutualGuildData &guild) m_name.set_markup("" + Glib::Markup::escape_text(data->Name) + ""); } else { m_icon.property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(24); - m_name.set_markup("Unknown server"); + m_name.set_markup(Glib::ustring::compose("%1", _("Unknown Server"))); } if (guild.Nick.has_value()) { diff --git a/src/windows/profile/userinfopane.cpp b/src/windows/profile/userinfopane.cpp index dc96e0fe..44c27778 100644 --- a/src/windows/profile/userinfopane.cpp +++ b/src/windows/profile/userinfopane.cpp @@ -2,6 +2,7 @@ #include +#include #include #include "abaddon.hpp" @@ -140,7 +141,7 @@ NotesContainer::NotesContainer() m_label.get_style_context()->add_class("profile-notes-label"); m_note.get_style_context()->add_class("profile-notes-text"); - m_label.set_markup("NOTE"); + m_label.set_markup(Glib::ustring::compose("%1", _("NOTE"))); m_label.set_halign(Gtk::ALIGN_START); m_note.set_wrap_mode(Gtk::WRAP_WORD_CHAR); @@ -186,7 +187,7 @@ NotesContainer::type_signal_update_note NotesContainer::signal_update_note() { BioContainer::BioContainer() : Gtk::Box(Gtk::ORIENTATION_VERTICAL) { - m_label.set_markup("ABOUT ME"); + m_label.set_markup(Glib::ustring::compose("%1", _("ABOUT ME"))); m_label.set_halign(Gtk::ALIGN_START); m_bio.set_halign(Gtk::ALIGN_START); m_bio.set_line_wrap(true); @@ -212,7 +213,7 @@ ProfileUserInfoPane::ProfileUserInfoPane(Snowflake ID) m_note.signal_update_note().connect([this](const Glib::ustring ¬e) { auto cb = [](DiscordError code) { if (code != DiscordError::NONE) { - Gtk::MessageDialog dlg("Failed to set note", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + Gtk::MessageDialog dlg(_("Failed to set note"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); } @@ -234,7 +235,7 @@ ProfileUserInfoPane::ProfileUserInfoPane(Snowflake ID) m_created.set_halign(Gtk::ALIGN_START); m_created.set_margin_top(5); - m_created.set_text("Account created: " + ID.GetLocalTimestamp()); + m_created.set_text(_("Account created: ") + ID.GetLocalTimestamp()); m_conns.set_halign(Gtk::ALIGN_START); m_conns.set_hexpand(true); diff --git a/src/windows/profilewindow.cpp b/src/windows/profilewindow.cpp index 4547ae41..15232daf 100644 --- a/src/windows/profilewindow.cpp +++ b/src/windows/profilewindow.cpp @@ -1,5 +1,7 @@ #include "profilewindow.hpp" +#include + #include "abaddon.hpp" #include "discord/user.hpp" #include "util.hpp" @@ -75,9 +77,9 @@ ProfileWindow::ProfileWindow(Snowflake user_id) m_switcher.set_halign(Gtk::ALIGN_START); m_switcher.set_hexpand(true); - m_stack.add(m_pane_info, "info", "User Info"); - m_stack.add(m_pane_guilds, "guilds", "Mutual Servers"); - m_stack.add(m_pane_friends, "friends", "Mutual Friends"); + m_stack.add(m_pane_info, "info", _("User Info")); + m_stack.add(m_pane_guilds, "guilds", _("Mutual Servers")); + m_stack.add(m_pane_friends, "friends", _("Mutual Friends")); m_badges.set_valign(Gtk::ALIGN_CENTER); m_badges_scroll.set_hexpand(true); @@ -108,7 +110,7 @@ void ProfileWindow::OnFetchProfile(const UserProfileData &data) { m_pane_guilds.SetMutualGuilds(data.MutualGuilds); if (data.LegacyUsername.has_value()) { - m_username.set_tooltip_text("Originally known as " + *data.LegacyUsername); + m_username.set_tooltip_text(Glib::ustring::compose(_("Originally known as %1"), *data.LegacyUsername)); } for (auto child : m_badges.get_children()) { diff --git a/src/windows/threadswindow.cpp b/src/windows/threadswindow.cpp index 81046d25..b7c65568 100644 --- a/src/windows/threadswindow.cpp +++ b/src/windows/threadswindow.cpp @@ -1,17 +1,19 @@ #include "threadswindow.hpp" +#include + #include "abaddon.hpp" ThreadsWindow::ThreadsWindow(const ChannelData &channel) : m_channel_id(channel.ID) - , m_filter_public(m_group, "Public") - , m_filter_private(m_group, "Private") + , m_filter_public(m_group, _("Public")) + , m_filter_private(m_group, _("Private")) , m_box(Gtk::ORIENTATION_VERTICAL) , m_active(channel, sigc::mem_fun(*this, &ThreadsWindow::ListFilterFunc)) , m_archived(channel, sigc::mem_fun(*this, &ThreadsWindow::ListFilterFunc)) { set_name("threads-window"); set_default_size(450, 375); - set_title("#" + *channel.Name + " - Threads"); + set_title(Glib::ustring::compose(_("#%1 - Threads"), *channel.Name)); set_position(Gtk::WIN_POS_CENTER); get_style_context()->add_class("app-window"); get_style_context()->add_class("app-popup"); @@ -27,8 +29,8 @@ ThreadsWindow::ThreadsWindow(const ChannelData &channel) m_switcher.set_halign(Gtk::ALIGN_CENTER); m_switcher.set_stack(m_stack); - m_stack.add(m_active, "active", "Active Threads"); - m_stack.add(m_archived, "archived", "Archived Threads"); + m_stack.add(m_active, "active", _("Active Threads")); + m_stack.add(m_archived, "archived", _("Archived Threads")); m_filter_buttons.set_homogeneous(true); m_filter_buttons.set_halign(Gtk::ALIGN_CENTER); diff --git a/src/windows/voice/voicewindow.cpp b/src/windows/voice/voicewindow.cpp index e59705a2..08e35ae0 100644 --- a/src/windows/voice/voicewindow.cpp +++ b/src/windows/voice/voicewindow.cpp @@ -5,6 +5,8 @@ #include "voicewindow.hpp" +#include + #include "abaddon.hpp" #include "audio/manager.hpp" #include "components/lazyimage.hpp" @@ -17,18 +19,18 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) : m_main(Gtk::ORIENTATION_VERTICAL) , m_controls(Gtk::ORIENTATION_HORIZONTAL) - , m_mute("Mute") - , m_deafen("Deafen") - , m_noise_suppression("Suppress Noise") - , m_mix_mono("Mix Mono") - , m_stage_command("Request to Speak") - , m_disconnect("Disconnect") - , m_stage_invite_lbl("You've been invited to speak") - , m_stage_accept("Accept") - , m_stage_decline("Decline") + , m_mute(_("Mute")) + , m_deafen(_("Deafen")) + , m_noise_suppression(_("Suppress Noise")) + , m_mix_mono(_("Mix Mono")) + , m_stage_command(_("Request to Speak")) + , m_disconnect(_("Disconnect")) + , m_stage_invite_lbl(_("You've been invited to speak")) + , m_stage_accept(_("Accept")) + , m_stage_decline(_("Decline")) , m_channel_id(channel_id) - , m_menu_view("View") - , m_menu_view_settings("More _Settings", true) { + , m_menu_view(_("View")) + , m_menu_view_settings(_("More _Settings"), true) { get_style_context()->add_class("app-window"); set_default_size(300, 400); @@ -91,10 +93,10 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) m_vad_combo.set_valign(Gtk::ALIGN_END); m_vad_combo.set_hexpand(true); m_vad_combo.set_halign(Gtk::ALIGN_FILL); - m_vad_combo.set_tooltip_text( + m_vad_combo.set_tooltip_text(_( "Voice Activation Detection method\n" "Gate - Simple volume threshold. Slider changes threshold\n" - "RNNoise - Heavier on CPU. Slider changes probability threshold"); + "RNNoise - Heavier on CPU. Slider changes probability threshold")); m_vad_combo.append("gate", "Gate"); #ifdef WITH_RNNOISE m_vad_combo.append("rnnoise", "RNNoise"); @@ -175,8 +177,8 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) auto *sliders_sliders = Gtk::make_managed(); sliders_container->pack_start(*sliders_labels, false, true, 2); sliders_container->pack_start(*sliders_sliders); - sliders_labels->pack_start(*Gtk::make_managed("Threshold", Gtk::ALIGN_END)); - sliders_labels->pack_start(*Gtk::make_managed("Gain", Gtk::ALIGN_END)); + sliders_labels->pack_start(*Gtk::make_managed(_("Threshold"), Gtk::ALIGN_END)); + sliders_labels->pack_start(*Gtk::make_managed(_("Gain"), Gtk::ALIGN_END)); sliders_sliders->pack_start(m_vad_param); sliders_sliders->pack_start(m_capture_gain); @@ -185,9 +187,9 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) auto *combos_combos = Gtk::make_managed(); combos_container->pack_start(*combos_labels, false, true, 6); combos_container->pack_start(*combos_combos, Gtk::PACK_EXPAND_WIDGET, 6); - combos_labels->pack_start(*Gtk::make_managed("VAD Method", Gtk::ALIGN_END)); - combos_labels->pack_start(*Gtk::make_managed("Output Device", Gtk::ALIGN_END)); - combos_labels->pack_start(*Gtk::make_managed("Input Device", Gtk::ALIGN_END)); + combos_labels->pack_start(*Gtk::make_managed(_("VAD Method"), Gtk::ALIGN_END)); + combos_labels->pack_start(*Gtk::make_managed(_("Output Device"), Gtk::ALIGN_END)); + combos_labels->pack_start(*Gtk::make_managed(_("Input Device"), Gtk::ALIGN_END)); combos_combos->pack_start(m_vad_combo); combos_combos->pack_start(m_playback_combo); combos_combos->pack_start(m_capture_combo); @@ -230,10 +232,10 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) Abaddon::Get().GetDiscordClient().DeclineInviteToSpeak(m_channel_id, NOOP_CALLBACK); }); - m_speakers_label.set_markup("Speakers"); + m_speakers_label.set_markup(Glib::ustring::compose("%1", _("Speakers"))); if (m_is_stage) m_listing.pack_start(m_speakers_label, false, true); m_listing.pack_start(m_speakers_list, false, true); - m_audience_label.set_markup("Audience"); + m_audience_label.set_markup(Glib::ustring::compose("%1", _("Audience"))); if (m_is_stage) m_listing.pack_start(m_audience_label, false, true); if (m_is_stage) m_listing.pack_start(m_audience_list, false, true); m_scroll.add(m_listing); @@ -254,7 +256,7 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) m_main.pack_start(m_buttons, false, true); m_main.pack_start(m_stage_invite_box, false, true); m_main.pack_start(m_vad_value, false, true); - m_main.pack_start(*Gtk::make_managed("Input Settings"), false, true); + m_main.pack_start(*Gtk::make_managed(_("Input Settings")), false, true); m_main.pack_start(*sliders_container, false, true); m_main.pack_start(m_scroll); m_stage_topic_label.set_ellipsize(Pango::ELLIPSIZE_END); @@ -368,20 +370,20 @@ void VoiceWindow::UpdateStageCommand() { m_stage_invite_box.set_visible(is_invited_to_speak); if (is_speaker) { - m_stage_command.set_label("Leave the Stage"); + m_stage_command.set_label(_("Leave the Stage")); } else if (is_moderator) { - m_stage_command.set_label("Speak on Stage"); + m_stage_command.set_label(_("Speak on Stage")); } else if (m_has_requested_to_speak) { - m_stage_command.set_label("Cancel Request"); + m_stage_command.set_label(_("Cancel Request")); } else if (is_invited_to_speak) { - m_stage_command.set_label("Decline Invite"); + m_stage_command.set_label(_("Decline Invite")); } else { - m_stage_command.set_label("Request to Speak"); + m_stage_command.set_label(_("Request to Speak")); } } void VoiceWindow::UpdateStageTopicLabel(const std::string &topic) { - m_stage_topic_label.set_markup("Topic: " + topic); + m_stage_topic_label.set_markup(_("Topic: ") + topic); } void VoiceWindow::OnUserConnect(Snowflake user_id, Snowflake to_channel_id) { diff --git a/src/windows/voicesettingswindow.cpp b/src/windows/voicesettingswindow.cpp index 90d07172..823c89a7 100644 --- a/src/windows/voicesettingswindow.cpp +++ b/src/windows/voicesettingswindow.cpp @@ -4,6 +4,8 @@ #include +#include + #include "abaddon.hpp" #include "audio/manager.hpp" #include "voicesettingswindow.hpp" @@ -16,45 +18,45 @@ VoiceSettingsWindow::VoiceSettingsWindow() get_style_context()->add_class("voice-settings-window"); set_default_size(300, 300); - m_encoding_mode.append("Voice"); - m_encoding_mode.append("Music"); - m_encoding_mode.append("Restricted"); + m_encoding_mode.append("voice", _("Voice")); + m_encoding_mode.append("music", _("Music")); + m_encoding_mode.append("restricted", _("Restricted")); m_encoding_mode.set_tooltip_text( - "Sets the coding mode for the Opus encoder\n" + _("Sets the coding mode for the Opus encoder\n" "Voice - Optimize for voice quality\n" "Music - Optimize for non-voice signals incl. music\n" - "Restricted - Optimize for non-voice, low latency. Not recommended"); + "Restricted - Optimize for non-voice, low latency. Not recommended")); const auto mode = Abaddon::Get().GetAudio().GetEncodingApplication(); if (mode == OPUS_APPLICATION_VOIP) { - m_encoding_mode.set_active(0); + m_encoding_mode.set_active_id("voice"); } else if (mode == OPUS_APPLICATION_AUDIO) { - m_encoding_mode.set_active(1); + m_encoding_mode.set_active_id("music"); } else if (mode == OPUS_APPLICATION_RESTRICTED_LOWDELAY) { - m_encoding_mode.set_active(2); + m_encoding_mode.set_active_id("restricted"); } m_encoding_mode.signal_changed().connect([this]() { - const auto mode = m_encoding_mode.get_active_text(); + const auto mode = m_encoding_mode.get_active_id(); auto &audio = Abaddon::Get().GetAudio(); - if (mode == "Voice") { + if (mode == "voice") { audio.SetEncodingApplication(OPUS_APPLICATION_VOIP); - } else if (mode == "Music") { + } else if (mode == "music") { spdlog::get("audio")->debug("music/audio"); audio.SetEncodingApplication(OPUS_APPLICATION_AUDIO); - } else if (mode == "Restricted") { + } else if (mode == "restricted") { audio.SetEncodingApplication(OPUS_APPLICATION_RESTRICTED_LOWDELAY); } }); - m_signal.append("Auto"); - m_signal.append("Voice"); - m_signal.append("Music"); + m_signal.append("auto", _("Auto")); + m_signal.append("voice", _("Voice")); + m_signal.append("music", _("Music")); m_signal.set_tooltip_text( - "Signal hint. Tells Opus what the current signal is\n" + _("Signal hint. Tells Opus what the current signal is\n" "Auto - Let Opus figure it out\n" "Voice - Tell Opus it's a voice signal\n" - "Music - Tell Opus it's a music signal"); + "Music - Tell Opus it's a music signal")); const auto signal = Abaddon::Get().GetAudio().GetSignalHint(); if (signal == OPUS_AUTO) { @@ -66,13 +68,13 @@ VoiceSettingsWindow::VoiceSettingsWindow() } m_signal.signal_changed().connect([this]() { - const auto signal = m_signal.get_active_text(); + const auto signal = m_signal.get_active_id(); auto &audio = Abaddon::Get().GetAudio(); - if (signal == "Auto") { + if (signal == "auto") { audio.SetSignalHint(OPUS_AUTO); - } else if (signal == "Voice") { + } else if (signal == "voice") { audio.SetSignalHint(OPUS_SIGNAL_VOICE); - } else if (signal == "Music") { + } else if (signal == "music") { audio.SetSignalHint(OPUS_SIGNAL_MUSIC); } }); @@ -125,10 +127,10 @@ VoiceSettingsWindow::VoiceSettingsWindow() auto *widgets = Gtk::make_managed(); layout->pack_start(*labels, false, true, 5); layout->pack_start(*widgets); - labels->pack_start(*Gtk::make_managed("Coding Mode", Gtk::ALIGN_END)); - labels->pack_start(*Gtk::make_managed("Signal Hint", Gtk::ALIGN_END)); - labels->pack_start(*Gtk::make_managed("Bitrate", Gtk::ALIGN_END)); - labels->pack_start(*Gtk::make_managed("Gain", Gtk::ALIGN_END)); + labels->pack_start(*Gtk::make_managed(_("Coding Mode"), Gtk::ALIGN_END)); + labels->pack_start(*Gtk::make_managed(_("Signal Hint"), Gtk::ALIGN_END)); + labels->pack_start(*Gtk::make_managed(_("Bitrate"), Gtk::ALIGN_END)); + labels->pack_start(*Gtk::make_managed(_("Gain"), Gtk::ALIGN_END)); widgets->pack_start(m_encoding_mode); widgets->pack_start(m_signal); widgets->pack_start(m_bitrate);