diff --git a/.github/labeler.yml b/.github/labeler.yml index 54f2757b0..871f9945f 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -33,3 +33,11 @@ kernel: infra: - changed-files: - any-glob-to-any-file: ['.github/**', 'distribution/**', 'Directory.Packages.props'] + +documentation: +- changed-files: + - any-glob-to-any-file: 'docs/**' + +ldn: +- changed-files: + - any-glob-to-any-file: 'src/Ryujinx.HLE/HOS/Services/Ldn/**' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b678e5f8e..21dc3eb0b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -122,7 +122,7 @@ jobs: - name: Upload Ryujinx.Headless.SDL2 artifact uses: actions/upload-artifact@v4 with: - name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} + name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} path: publish_sdl2_headless if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' @@ -185,6 +185,6 @@ jobs: - name: Upload Ryujinx.Headless.SDL2 artifact uses: actions/upload-artifact@v4 with: - name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal + name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal path: "publish_headless/*.tar.gz" if: github.event_name == 'pull_request' diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index d102beaa3..b352e82d7 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -54,7 +54,19 @@ jobs: with: name: "Canary ${{ steps.version_info.outputs.build_version }}" tag: ${{ steps.version_info.outputs.build_version }} - body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" + body: | + # Canary builds: + + These builds are experimental and may sometimes not work, use [regular builds](https://github.com/${{ github.repository }}/releases/latest) instead if that sounds like something you don't want to deal with. + + | Platform | Artifact | + |--|--| + | Windows 64 bit | [Canary Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) | + | Linux 64 bit | [Canary Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) | + | Linux arm 64 bit | [Canary Linux arm Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) | + | macOS | [Canary macOS artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) | + + **Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }} omitBodyDuringUpdate: true owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }} repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }} @@ -103,20 +115,20 @@ jobs: - name: Publish run: | - dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained -p:IncludeNativeLibrariesForSelfExtract=true - dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained -p:IncludeNativeLibrariesForSelfExtract=true + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained - name: Packing Windows builds if: matrix.platform.os == 'windows-latest' run: | pushd publish_ava rm publish/libarmeilleure-jitsupport.dylib - 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish + 7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish popd pushd publish_sdl2_headless rm publish/libarmeilleure-jitsupport.dylib - 7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish + 7z a ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish popd shell: bash @@ -126,13 +138,13 @@ jobs: pushd publish_ava rm publish/libarmeilleure-jitsupport.dylib chmod +x publish/Ryujinx.sh publish/Ryujinx - tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish + tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish popd pushd publish_sdl2_headless rm publish/libarmeilleure-jitsupport.dylib chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2 - tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish + tar -czvf ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish popd shell: bash @@ -181,7 +193,19 @@ jobs: artifacts: "release_output/*.tar.gz,release_output/*.zip" #artifacts: "release_output/*.tar.gz,release_output/*.zip/*AppImage*" tag: ${{ steps.version_info.outputs.build_version }} - body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" + body: | + # Canary builds: + + These builds are experimental and may sometimes not work, use [regular builds](https://github.com/GreemDev/Ryujinx/releases/latest) instead if that sounds like something you don't want to deal with. + + | Platform | Artifact | + |--|--| + | Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip | + | Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | + | Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | + | Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | + + "**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" omitBodyDuringUpdate: true allowUpdates: true replacesArtifacts: true @@ -236,11 +260,11 @@ jobs: - name: Publish macOS Ryujinx run: | - ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release + ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1 - name: Publish macOS Ryujinx.Headless.SDL2 run: | - ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release + ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1 - name: Pushing new release uses: ncipollo/release-action@v1 @@ -248,7 +272,19 @@ jobs: name: "Canary ${{ steps.version_info.outputs.build_version }}" artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz" tag: ${{ steps.version_info.outputs.build_version }} - body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" + body: | + # Canary builds: + + These builds are experimental and may sometimes not work, use [regular builds](https://github.com/GreemDev/Ryujinx/releases/latest) instead if that sounds like something you don't want to deal with. + + | Platform | Artifact | + |--|--| + | Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip | + | Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | + | Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | + | Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | + + "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" omitBodyDuringUpdate: true allowUpdates: true replacesArtifacts: true diff --git a/.github/workflows/nightly_pr_comment.yml b/.github/workflows/nightly_pr_comment.yml index 64705b6ee..85a6e2de4 100644 --- a/.github/workflows/nightly_pr_comment.yml +++ b/.github/workflows/nightly_pr_comment.yml @@ -38,12 +38,12 @@ jobs: return core.error(`No artifacts found`); } let body = `Download the artifacts for this pull request:\n`; - let hidden_headless_artifacts = `\n\n
GUI-less (SDL2)\n`; + let hidden_headless_artifacts = `\n\n
GUI-less\n`; let hidden_debug_artifacts = `\n\n
Only for Developers\n`; for (const art of artifacts) { if(art.name.includes('Debug')) { hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; - } else if(art.name.includes('sdl2-ryujinx-headless')) { + } else if(art.name.includes('nogui-ryujinx')) { hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; } else { body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d1ea8e449..815321dfe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,7 +53,16 @@ jobs: with: name: ${{ steps.version_info.outputs.build_version }} tag: ${{ steps.version_info.outputs.build_version }} - body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}" + body: | + # Regular builds: + | Platform | Artifact | + |--|--| + | Windows 64 bit | [Release Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) | + | Linux 64 bit | [Release Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) | + | Linux arm 64 bit | [Release Linux arm Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) | + | macOS | [Release macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) | + + **Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }} omitBodyDuringUpdate: true owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }} repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }} @@ -102,8 +111,8 @@ jobs: - name: Publish run: | - dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained -p:IncludeNativeLibrariesForSelfExtract=true - dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained -p:IncludeNativeLibrariesForSelfExtract=true + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained - name: Packing Windows builds if: matrix.platform.os == 'windows-latest' @@ -115,7 +124,7 @@ jobs: pushd publish_sdl2_headless rm libarmeilleure-jitsupport.dylib - 7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish + 7z a ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish popd shell: bash @@ -166,7 +175,7 @@ jobs: pushd publish_sdl2_headless chmod +x Ryujinx.sh Ryujinx.Headless.SDL2 - tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish + tar -czvf ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish popd shell: bash @@ -176,7 +185,16 @@ jobs: name: ${{ steps.version_info.outputs.build_version }} artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*" tag: ${{ steps.version_info.outputs.build_version }} - body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}" + body: | + # Regular builds: + | Platform | Artifact | + |--|--| + | Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip | + | Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | + | Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | + | Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | + + "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}" omitBodyDuringUpdate: true allowUpdates: true replacesArtifacts: true @@ -231,11 +249,11 @@ jobs: - name: Publish macOS Ryujinx run: | - ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release + ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0 - name: Publish macOS Ryujinx.Headless.SDL2 run: | - ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release + ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0 - name: Pushing new release uses: ncipollo/release-action@v1 @@ -243,7 +261,16 @@ jobs: name: ${{ steps.version_info.outputs.build_version }} artifacts: "publish/*.tar.gz, publish_headless/*.tar.gz" tag: ${{ steps.version_info.outputs.build_version }} - body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}" + body: | + # Regular builds: + | Platform | Artifact | + |--|--| + | Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip | + | Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | + | Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | + | Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | + + "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}" omitBodyDuringUpdate: true allowUpdates: true replacesArtifacts: true diff --git a/.gitignore b/.gitignore index f71237b1a..9a192926f 100644 --- a/.gitignore +++ b/.gitignore @@ -175,3 +175,6 @@ PublishProfiles/ # Glade backup files *.glade~ + +# Ignore MacOS Attribute Files +._* diff --git a/Directory.Packages.props b/Directory.Packages.props index c0ace079d..7059af0e0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -38,7 +38,7 @@ - + @@ -52,4 +52,4 @@ - \ No newline at end of file + diff --git a/README.md b/README.md index 3bc223f3a..f5bd87c7f 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,26 @@ -

+ + + + + +
+ Ryujinx + + +# Ryujinx + +[![Release workflow](https://github.com/GreemDev/Ryujinx/actions/workflows/release.yml/badge.svg)](https://github.com/GreemDev/Ryujinx/actions/workflows/release.yml) +[![Latest release](https://img.shields.io/github/v/release/GreemDev/Ryujinx)](https://github.com/GreemDev/Ryujinx/releases/latest)
- Ryujinx -
- Ryujinx -
- (REE-YOU-JINX) -
- - - - - Latest Release - -
- - - - - Latest Canary Release - - +[![Canary workflow](https://github.com/GreemDev/Ryujinx/actions/workflows/canary.yml/badge.svg)](https://github.com/GreemDev/Ryujinx/actions/workflows/canary.yml) +[![Latest canary release](https://img.shields.io/github/v/release/GreemDev/Ryujinx-Canary?label=canary)](https://github.com/GreemDev/Ryujinx-Canary/releases/latest) +

Ryujinx is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#. This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds. It was written from scratch and development on the project began in September 2017. - Ryujinx is available on Github under the MIT license. + Ryujinx is available on GitHub under the MIT license.

@@ -42,7 +33,7 @@ Guides and documentation can be found on the Wiki tab.

- If you would like a version more preservative fork of Ryujinx, check out ryujinx-mirror. + If you would like a more preservative fork of Ryujinx, check out ryujinx-mirror.

diff --git a/distribution/linux/Ryujinx.sh b/distribution/linux/Ryujinx.sh index 30eb14399..daeea9bfd 100755 --- a/distribution/linux/Ryujinx.sh +++ b/distribution/linux/Ryujinx.sh @@ -14,7 +14,7 @@ if [ -z "$RYUJINX_BIN" ]; then exit 1 fi -COMMAND="env DOTNET_EnableAlternateStackCheck=1" +COMMAND="env LANG=C.UTF-8 DOTNET_EnableAlternateStackCheck=1" if command -v gamemoderun > /dev/null 2>&1; then COMMAND="$COMMAND gamemoderun" diff --git a/distribution/macos/Info.plist b/distribution/macos/Info.plist index 53929f95e..2602f9905 100644 --- a/distribution/macos/Info.plist +++ b/distribution/macos/Info.plist @@ -40,11 +40,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.1 + 1.2 CFBundleSignature ???? CFBundleVersion - 1.1.0 + 1.2.0 NSHighResolutionCapable CSResourcesFileMapped diff --git a/distribution/macos/Ryujinx.icns b/distribution/macos/Ryujinx.icns index 1bb88a5d7..fd5cd7f7e 100644 Binary files a/distribution/macos/Ryujinx.icns and b/distribution/macos/Ryujinx.icns differ diff --git a/distribution/macos/create_macos_build_ava.sh b/distribution/macos/create_macos_build_ava.sh index 80bd6662c..b19fa4863 100755 --- a/distribution/macos/create_macos_build_ava.sh +++ b/distribution/macos/create_macos_build_ava.sh @@ -2,8 +2,8 @@ set -e -if [ "$#" -lt 7 ]; then - echo "usage " +if [ "$#" -lt 8 ]; then + echo "usage " exit 1 fi @@ -18,10 +18,11 @@ ENTITLEMENTS_FILE_PATH=$(readlink -f "$4") VERSION=$5 SOURCE_REVISION_ID=$6 CONFIGURATION=$7 -EXTRA_ARGS=$8 +CANARY=$8 -if [ "$VERSION" == "1.1.0" ]; -then +if [ "$CANARY" == "1" ]; then + RELEASE_TAR_FILE_NAME=ryujinx-canary-$VERSION-macos_universal.app.tar +elif [ "$VERSION" == "1.1.0" ]; then RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar else RELEASE_TAR_FILE_NAME=ryujinx-$VERSION-macos_universal.app.tar @@ -61,7 +62,7 @@ mkdir -p "$OUTPUT_DIRECTORY" cp -R "$ARM64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE" rm "$UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH" -# Make it libraries universal +# Make its libraries universal python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_BUNDLE" "$X64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE" "**/*.dylib" if ! [ -x "$(command -v lipo)" ]; diff --git a/distribution/macos/create_macos_build_headless.sh b/distribution/macos/create_macos_build_headless.sh index 2715699d0..01951d878 100755 --- a/distribution/macos/create_macos_build_headless.sh +++ b/distribution/macos/create_macos_build_headless.sh @@ -2,8 +2,8 @@ set -e -if [ "$#" -lt 7 ]; then - echo "usage " +if [ "$#" -lt 8 ]; then + echo "usage " exit 1 fi @@ -18,13 +18,14 @@ ENTITLEMENTS_FILE_PATH=$(readlink -f "$4") VERSION=$5 SOURCE_REVISION_ID=$6 CONFIGURATION=$7 -EXTRA_ARGS=$8 +CANARY=$8 -if [ "$VERSION" == "1.1.0" ]; -then - RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar +if [ "$CANARY" == "1" ]; then + RELEASE_TAR_FILE_NAME=nogui-ryujinx-canary-$VERSION-macos_universal.tar +elif [ "$VERSION" == "1.1.0" ]; then + RELEASE_TAR_FILE_NAME=nogui-ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar else - RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$VERSION-macos_universal.tar + RELEASE_TAR_FILE_NAME=nogui-ryujinx-$VERSION-macos_universal.tar fi ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64" @@ -56,7 +57,7 @@ mkdir -p "$OUTPUT_DIRECTORY" cp -R "$ARM64_OUTPUT/" "$UNIVERSAL_OUTPUT" rm "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH" -# Make it libraries universal +# Make its libraries universal python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTPUT" "$X64_OUTPUT" "$UNIVERSAL_OUTPUT" "**/*.dylib" if ! [ -x "$(command -v lipo)" ]; diff --git a/distribution/macos/updater.sh b/distribution/macos/updater.sh index 12e4c3aa1..0465d7c91 100755 --- a/distribution/macos/updater.sh +++ b/distribution/macos/updater.sh @@ -17,7 +17,7 @@ error_handler() { set the button_pressed to the button returned of the result if the button_pressed is \"Open Download Page\" then - open location \"https://ryujinx.org/download\" + open location \"https://ryujinx.app/download\" end if """ @@ -54,4 +54,4 @@ if [ "$#" -le 3 ]; then open -a "$INSTALL_DIRECTORY" else open -a "$INSTALL_DIRECTORY" --args "${APP_ARGUMENTS[@]}" -fi \ No newline at end of file +fi diff --git a/distribution/misc/Logo.svg b/distribution/misc/Logo.svg index d3327f2ef..00bba42f0 100644 --- a/distribution/misc/Logo.svg +++ b/distribution/misc/Logo.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/distribution/misc/macOS.svg b/distribution/misc/macOS.svg new file mode 100644 index 000000000..4bdd453a8 --- /dev/null +++ b/distribution/misc/macOS.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ARMeilleure/ARMeilleure.csproj b/src/ARMeilleure/ARMeilleure.csproj index 550e50c26..4b67fdb3b 100644 --- a/src/ARMeilleure/ARMeilleure.csproj +++ b/src/ARMeilleure/ARMeilleure.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/ARMeilleure/Common/AddressTable.cs b/src/ARMeilleure/Common/AddressTable.cs deleted file mode 100644 index a3ffaf470..000000000 --- a/src/ARMeilleure/Common/AddressTable.cs +++ /dev/null @@ -1,252 +0,0 @@ -using ARMeilleure.Diagnostics; -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Common -{ - ///

- /// Represents a table of guest address to a value. - /// - /// Type of the value - public unsafe class AddressTable : IDisposable where TEntry : unmanaged - { - /// - /// Represents a level in an . - /// - public readonly struct Level - { - /// - /// Gets the index of the in the guest address. - /// - public int Index { get; } - - /// - /// Gets the length of the in the guest address. - /// - public int Length { get; } - - /// - /// Gets the mask which masks the bits used by the . - /// - public ulong Mask => ((1ul << Length) - 1) << Index; - - /// - /// Initializes a new instance of the structure with the specified - /// and . - /// - /// Index of the - /// Length of the - public Level(int index, int length) - { - (Index, Length) = (index, length); - } - - /// - /// Gets the value of the from the specified guest . - /// - /// Guest address - /// Value of the from the specified guest - public int GetValue(ulong address) - { - return (int)((address & Mask) >> Index); - } - } - - private bool _disposed; - private TEntry** _table; - private readonly List _pages; - - /// - /// Gets the bits used by the of the instance. - /// - public ulong Mask { get; } - - /// - /// Gets the s used by the instance. - /// - public Level[] Levels { get; } - - /// - /// Gets or sets the default fill value of newly created leaf pages. - /// - public TEntry Fill { get; set; } - - /// - /// Gets the base address of the . - /// - /// instance was disposed - public nint Base - { - get - { - ObjectDisposedException.ThrowIf(_disposed, this); - - lock (_pages) - { - return (nint)GetRootPage(); - } - } - } - - /// - /// Constructs a new instance of the class with the specified list of - /// . - /// - /// is null - /// Length of is less than 2 - public AddressTable(Level[] levels) - { - ArgumentNullException.ThrowIfNull(levels); - - if (levels.Length < 2) - { - throw new ArgumentException("Table must be at least 2 levels deep.", nameof(levels)); - } - - _pages = new List(capacity: 16); - - Levels = levels; - Mask = 0; - - foreach (var level in Levels) - { - Mask |= level.Mask; - } - } - - /// - /// Determines if the specified is in the range of the - /// . - /// - /// Guest address - /// if is valid; otherwise - public bool IsValid(ulong address) - { - return (address & ~Mask) == 0; - } - - /// - /// Gets a reference to the value at the specified guest . - /// - /// Guest address - /// Reference to the value at the specified guest - /// instance was disposed - /// is not mapped - public ref TEntry GetValue(ulong address) - { - ObjectDisposedException.ThrowIf(_disposed, this); - - if (!IsValid(address)) - { - throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address)); - } - - lock (_pages) - { - return ref GetPage(address)[Levels[^1].GetValue(address)]; - } - } - - /// - /// Gets the leaf page for the specified guest . - /// - /// Guest address - /// Leaf page for the specified guest - private TEntry* GetPage(ulong address) - { - TEntry** page = GetRootPage(); - - for (int i = 0; i < Levels.Length - 1; i++) - { - ref Level level = ref Levels[i]; - ref TEntry* nextPage = ref page[level.GetValue(address)]; - - if (nextPage == null) - { - ref Level nextLevel = ref Levels[i + 1]; - - nextPage = i == Levels.Length - 2 ? - (TEntry*)Allocate(1 << nextLevel.Length, Fill, leaf: true) : - (TEntry*)Allocate(1 << nextLevel.Length, nint.Zero, leaf: false); - } - - page = (TEntry**)nextPage; - } - - return (TEntry*)page; - } - - /// - /// Lazily initialize and get the root page of the . - /// - /// Root page of the - private TEntry** GetRootPage() - { - if (_table == null) - { - _table = (TEntry**)Allocate(1 << Levels[0].Length, fill: nint.Zero, leaf: false); - } - - return _table; - } - - /// - /// Allocates a block of memory of the specified type and length. - /// - /// Type of elements - /// Number of elements - /// Fill value - /// if leaf; otherwise - /// Allocated block - private nint Allocate(int length, T fill, bool leaf) where T : unmanaged - { - var size = sizeof(T) * length; - var page = (nint)NativeAllocator.Instance.Allocate((uint)size); - var span = new Span((void*)page, length); - - span.Fill(fill); - - _pages.Add(page); - - TranslatorEventSource.Log.AddressTableAllocated(size, leaf); - - return page; - } - - /// - /// Releases all resources used by the instance. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases all unmanaged and optionally managed resources used by the - /// instance. - /// - /// to dispose managed resources also; otherwise just unmanaged resouces - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - foreach (var page in _pages) - { - Marshal.FreeHGlobal(page); - } - - _disposed = true; - } - } - - /// - /// Frees resources used by the instance. - /// - ~AddressTable() - { - Dispose(false); - } - } -} diff --git a/src/ARMeilleure/Common/AddressTableLevel.cs b/src/ARMeilleure/Common/AddressTableLevel.cs new file mode 100644 index 000000000..af3b9b99f --- /dev/null +++ b/src/ARMeilleure/Common/AddressTableLevel.cs @@ -0,0 +1,44 @@ +namespace ARMeilleure.Common +{ + /// + /// Represents a level in an . + /// + public readonly struct AddressTableLevel + { + /// + /// Gets the index of the in the guest address. + /// + public int Index { get; } + + /// + /// Gets the length of the in the guest address. + /// + public int Length { get; } + + /// + /// Gets the mask which masks the bits used by the . + /// + public ulong Mask => ((1ul << Length) - 1) << Index; + + /// + /// Initializes a new instance of the structure with the specified + /// and . + /// + /// Index of the + /// Length of the + public AddressTableLevel(int index, int length) + { + (Index, Length) = (index, length); + } + + /// + /// Gets the value of the from the specified guest . + /// + /// Guest address + /// Value of the from the specified guest + public long GetValue(ulong address) + { + return (long)((address & Mask) >> Index); + } + } +} diff --git a/src/ARMeilleure/Common/AddressTablePresets.cs b/src/ARMeilleure/Common/AddressTablePresets.cs new file mode 100644 index 000000000..977e84a36 --- /dev/null +++ b/src/ARMeilleure/Common/AddressTablePresets.cs @@ -0,0 +1,75 @@ +namespace ARMeilleure.Common +{ + public static class AddressTablePresets + { + private static readonly AddressTableLevel[] _levels64Bit = + new AddressTableLevel[] + { + new(31, 17), + new(23, 8), + new(15, 8), + new( 7, 8), + new( 2, 5), + }; + + private static readonly AddressTableLevel[] _levels32Bit = + new AddressTableLevel[] + { + new(31, 17), + new(23, 8), + new(15, 8), + new( 7, 8), + new( 1, 6), + }; + + private static readonly AddressTableLevel[] _levels64BitSparseTiny = + new AddressTableLevel[] + { + new( 11, 28), + new( 2, 9), + }; + + private static readonly AddressTableLevel[] _levels32BitSparseTiny = + new AddressTableLevel[] + { + new( 10, 22), + new( 1, 9), + }; + + private static readonly AddressTableLevel[] _levels64BitSparseGiant = + new AddressTableLevel[] + { + new( 38, 1), + new( 2, 36), + }; + + private static readonly AddressTableLevel[] _levels32BitSparseGiant = + new AddressTableLevel[] + { + new( 31, 1), + new( 1, 30), + }; + + //high power will run worse on DDR3 systems and some DDR4 systems due to the higher ram utilization + //low power will never run worse than non-sparse, but for most systems it won't be necessary + //high power is always used, but I've left low power in here for future reference + public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse, bool lowPower = false) + { + if (sparse) + { + if (lowPower) + { + return for64Bits ? _levels64BitSparseTiny : _levels32BitSparseTiny; + } + else + { + return for64Bits ? _levels64BitSparseGiant : _levels32BitSparseGiant; + } + } + else + { + return for64Bits ? _levels64Bit : _levels32Bit; + } + } + } +} diff --git a/src/ARMeilleure/Common/Allocator.cs b/src/ARMeilleure/Common/Allocator.cs index 6905a614f..de6a77ebe 100644 --- a/src/ARMeilleure/Common/Allocator.cs +++ b/src/ARMeilleure/Common/Allocator.cs @@ -2,7 +2,7 @@ using System; namespace ARMeilleure.Common { - unsafe abstract class Allocator : IDisposable + public unsafe abstract class Allocator : IDisposable { public T* Allocate(ulong count = 1) where T : unmanaged { diff --git a/src/ARMeilleure/Common/IAddressTable.cs b/src/ARMeilleure/Common/IAddressTable.cs new file mode 100644 index 000000000..65077ec43 --- /dev/null +++ b/src/ARMeilleure/Common/IAddressTable.cs @@ -0,0 +1,51 @@ +using System; + +namespace ARMeilleure.Common +{ + public interface IAddressTable : IDisposable where TEntry : unmanaged + { + /// + /// True if the address table's bottom level is sparsely mapped. + /// This also ensures the second bottom level is filled with a dummy page rather than 0. + /// + bool Sparse { get; } + + /// + /// Gets the bits used by the of the instance. + /// + ulong Mask { get; } + + /// + /// Gets the s used by the instance. + /// + AddressTableLevel[] Levels { get; } + + /// + /// Gets or sets the default fill value of newly created leaf pages. + /// + TEntry Fill { get; set; } + + /// + /// Gets the base address of the . + /// + /// instance was disposed + nint Base { get; } + + /// + /// Determines if the specified is in the range of the + /// . + /// + /// Guest address + /// if is valid; otherwise + bool IsValid(ulong address); + + /// + /// Gets a reference to the value at the specified guest . + /// + /// Guest address + /// Reference to the value at the specified guest + /// instance was disposed + /// is not mapped + ref TEntry GetValue(ulong address); + } +} diff --git a/src/ARMeilleure/Common/NativeAllocator.cs b/src/ARMeilleure/Common/NativeAllocator.cs index ca5d3a850..ffcffa4bc 100644 --- a/src/ARMeilleure/Common/NativeAllocator.cs +++ b/src/ARMeilleure/Common/NativeAllocator.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; namespace ARMeilleure.Common { - unsafe sealed class NativeAllocator : Allocator + public unsafe sealed class NativeAllocator : Allocator { public static NativeAllocator Instance { get; } = new(); diff --git a/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs b/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs index 2009bafda..a602ea49e 100644 --- a/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs +++ b/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs @@ -193,6 +193,8 @@ namespace ARMeilleure.Instructions Operand hostAddress; + var table = context.FunctionTable; + // If address is mapped onto the function table, we can skip the table walk. Otherwise we fallback // onto the dispatch stub. if (guestAddress.Kind == OperandKind.Constant && context.FunctionTable.IsValid(guestAddress.Value)) @@ -203,6 +205,30 @@ namespace ARMeilleure.Instructions hostAddress = context.Load(OperandType.I64, hostAddressAddr); } + else if (table.Sparse) + { + // Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels. + // Deliberately attempts to avoid branches. + + Operand tableBase = !context.HasPtc ? + Const(table.Base) : + Const(table.Base, Ptc.FunctionTableSymbol); + + hostAddress = tableBase; + + for (int i = 0; i < table.Levels.Length; i++) + { + var level = table.Levels[i]; + int clearBits = 64 - (level.Index + level.Length); + + Operand index = context.ShiftLeft( + context.ShiftRightUI(context.ShiftLeft(guestAddress, Const(clearBits)), Const(clearBits + level.Index)), + Const(3) + ); + + hostAddress = context.Load(OperandType.I64, context.Add(hostAddress, index)); + } + } else { hostAddress = !context.HasPtc ? diff --git a/src/ARMeilleure/Instructions/InstEmitSystem.cs b/src/ARMeilleure/Instructions/InstEmitSystem.cs index 8c430fc23..11c1d0328 100644 --- a/src/ARMeilleure/Instructions/InstEmitSystem.cs +++ b/src/ARMeilleure/Instructions/InstEmitSystem.cs @@ -49,6 +49,9 @@ namespace ARMeilleure.Instructions case 0b11_011_1101_0000_011: EmitGetTpidrroEl0(context); return; + case 0b11_011_1101_0000_101: + EmitGetTpidr2El0(context); + return; case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break; @@ -84,6 +87,9 @@ namespace ARMeilleure.Instructions case 0b11_011_1101_0000_010: EmitSetTpidrEl0(context); return; + case 0b11_011_1101_0000_101: + EmitSetTpidr2El0(context); + return; default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); @@ -213,6 +219,17 @@ namespace ARMeilleure.Instructions SetIntOrZR(context, op.Rt, result); } + private static void EmitGetTpidr2El0(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + Operand nativeContext = context.LoadArgument(OperandType.I64, 0); + + Operand result = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidr2El0Offset()))); + + SetIntOrZR(context, op.Rt, result); + } + private static void EmitSetNzcv(ArmEmitterContext context) { OpCodeSystem op = (OpCodeSystem)context.CurrOp; @@ -274,5 +291,16 @@ namespace ARMeilleure.Instructions context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())), value); } + + private static void EmitSetTpidr2El0(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + Operand value = GetIntOrZR(context, op.Rt); + + Operand nativeContext = context.LoadArgument(OperandType.I64, 0); + + context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidr2El0Offset())), value); + } } } diff --git a/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs index 1b3689e3f..35747d7a4 100644 --- a/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs +++ b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs @@ -8,7 +8,7 @@ namespace ARMeilleure.Signal { public static class NativeSignalHandlerGenerator { - public const int MaxTrackedRanges = 8; + public const int MaxTrackedRanges = 16; private const int StructAddressOffset = 0; private const int StructWriteOffset = 4; diff --git a/src/ARMeilleure/State/NativeContext.cs b/src/ARMeilleure/State/NativeContext.cs index 628efde41..140b6f7a7 100644 --- a/src/ARMeilleure/State/NativeContext.cs +++ b/src/ARMeilleure/State/NativeContext.cs @@ -21,6 +21,7 @@ namespace ARMeilleure.State public ulong ExclusiveValueLow; public ulong ExclusiveValueHigh; public int Running; + public long Tpidr2El0; } private static NativeCtxStorage _dummyStorage = new(); @@ -176,6 +177,9 @@ namespace ARMeilleure.State public long GetTpidrroEl0() => GetStorage().TpidrroEl0; public void SetTpidrroEl0(long value) => GetStorage().TpidrroEl0 = value; + public long GetTpidr2El0() => GetStorage().Tpidr2El0; + public void SetTpidr2El0(long value) => GetStorage().Tpidr2El0 = value; + public int GetCounter() => GetStorage().Counter; public void SetCounter(int value) => GetStorage().Counter = value; @@ -232,6 +236,11 @@ namespace ARMeilleure.State return StorageOffset(ref _dummyStorage, ref _dummyStorage.TpidrroEl0); } + public static int GetTpidr2El0Offset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.Tpidr2El0); + } + public static int GetCounterOffset() { return StorageOffset(ref _dummyStorage, ref _dummyStorage.Counter); diff --git a/src/ARMeilleure/Translation/ArmEmitterContext.cs b/src/ARMeilleure/Translation/ArmEmitterContext.cs index 5d79171a2..82f12bb02 100644 --- a/src/ARMeilleure/Translation/ArmEmitterContext.cs +++ b/src/ARMeilleure/Translation/ArmEmitterContext.cs @@ -46,7 +46,7 @@ namespace ARMeilleure.Translation public IMemoryManager Memory { get; } public EntryTable CountTable { get; } - public AddressTable FunctionTable { get; } + public IAddressTable FunctionTable { get; } public TranslatorStubs Stubs { get; } public ulong EntryAddress { get; } @@ -62,7 +62,7 @@ namespace ARMeilleure.Translation public ArmEmitterContext( IMemoryManager memory, EntryTable countTable, - AddressTable funcTable, + IAddressTable funcTable, TranslatorStubs stubs, ulong entryAddress, bool highCq, diff --git a/src/ARMeilleure/Translation/PTC/Ptc.cs b/src/ARMeilleure/Translation/PTC/Ptc.cs index 8236150fe..841e5fefa 100644 --- a/src/ARMeilleure/Translation/PTC/Ptc.cs +++ b/src/ARMeilleure/Translation/PTC/Ptc.cs @@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0"; - private const uint InternalVersion = 6950; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 6997; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1"; @@ -41,6 +41,7 @@ namespace ARMeilleure.Translation.PTC public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1); public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2); public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3); + public static readonly Symbol FunctionTableSymbol = new(SymbolType.Special, 4); private const byte FillingByte = 0x00; private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest; @@ -101,7 +102,7 @@ namespace ARMeilleure.Translation.PTC Disable(); } - public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode) + public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode, string cacheSelector) { Wait(); @@ -127,6 +128,8 @@ namespace ARMeilleure.Translation.PTC DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault; _memoryMode = memoryMode; + Logger.Info?.Print(LogClass.Ptc, $"PPTC (v{InternalVersion}) Profile: {DisplayVersion}-{cacheSelector}"); + string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir); string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir); @@ -140,8 +143,8 @@ namespace ARMeilleure.Translation.PTC Directory.CreateDirectory(workPathBackup); } - CachePathActual = Path.Combine(workPathActual, DisplayVersion); - CachePathBackup = Path.Combine(workPathBackup, DisplayVersion); + CachePathActual = Path.Combine(workPathActual, DisplayVersion) + "-" + cacheSelector; + CachePathBackup = Path.Combine(workPathBackup, DisplayVersion) + "-" + cacheSelector; PreLoad(); Profiler.PreLoad(); @@ -706,6 +709,10 @@ namespace ARMeilleure.Translation.PTC { imm = translator.Stubs.DispatchStub; } + else if (symbol == FunctionTableSymbol) + { + imm = translator.FunctionTable.Base; + } if (imm == null) { diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs index 24fbd7621..162368782 100644 --- a/src/ARMeilleure/Translation/Translator.cs +++ b/src/ARMeilleure/Translation/Translator.cs @@ -22,33 +22,13 @@ namespace ARMeilleure.Translation { public class Translator { - private static readonly AddressTable.Level[] _levels64Bit = - new AddressTable.Level[] - { - new(31, 17), - new(23, 8), - new(15, 8), - new( 7, 8), - new( 2, 5), - }; - - private static readonly AddressTable.Level[] _levels32Bit = - new AddressTable.Level[] - { - new(31, 17), - new(23, 8), - new(15, 8), - new( 7, 8), - new( 1, 6), - }; - private readonly IJitMemoryAllocator _allocator; private readonly ConcurrentQueue> _oldFuncs; private readonly Ptc _ptc; internal TranslatorCache Functions { get; } - internal AddressTable FunctionTable { get; } + internal IAddressTable FunctionTable { get; } internal EntryTable CountTable { get; } internal TranslatorStubs Stubs { get; } internal TranslatorQueue Queue { get; } @@ -57,7 +37,7 @@ namespace ARMeilleure.Translation private Thread[] _backgroundTranslationThreads; private volatile int _threadCount; - public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, bool for64Bits) + public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, IAddressTable functionTable) { _allocator = allocator; Memory = memory; @@ -72,15 +52,15 @@ namespace ARMeilleure.Translation CountTable = new EntryTable(); Functions = new TranslatorCache(); - FunctionTable = new AddressTable(for64Bits ? _levels64Bit : _levels32Bit); + FunctionTable = functionTable; Stubs = new TranslatorStubs(FunctionTable); FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub; } - public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) + public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector) { - _ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type); + _ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type, cacheSelector); return _ptc; } diff --git a/src/ARMeilleure/Translation/TranslatorStubs.cs b/src/ARMeilleure/Translation/TranslatorStubs.cs index 364cca13c..bd9aed8d4 100644 --- a/src/ARMeilleure/Translation/TranslatorStubs.cs +++ b/src/ARMeilleure/Translation/TranslatorStubs.cs @@ -19,7 +19,7 @@ namespace ARMeilleure.Translation private bool _disposed; - private readonly AddressTable _functionTable; + private readonly IAddressTable _functionTable; private readonly Lazy _dispatchStub; private readonly Lazy _dispatchLoop; private readonly Lazy _contextWrapper; @@ -86,7 +86,7 @@ namespace ARMeilleure.Translation /// /// Function table used to store pointers to the functions that the guest code will call /// is null - public TranslatorStubs(AddressTable functionTable) + public TranslatorStubs(IAddressTable functionTable) { ArgumentNullException.ThrowIfNull(functionTable); diff --git a/src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj b/src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj index b5fd8f9e7..bdf46d688 100644 --- a/src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj +++ b/src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Audio.Backends.SDL2/Ryujinx.Audio.Backends.SDL2.csproj b/src/Ryujinx.Audio.Backends.SDL2/Ryujinx.Audio.Backends.SDL2.csproj index dd18e70a1..940e47308 100644 --- a/src/Ryujinx.Audio.Backends.SDL2/Ryujinx.Audio.Backends.SDL2.csproj +++ b/src/Ryujinx.Audio.Backends.SDL2/Ryujinx.Audio.Backends.SDL2.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj b/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj index 5c9423463..671a6ad5e 100644 --- a/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj +++ b/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj @@ -4,6 +4,7 @@ net8.0 true win-x64;osx-x64;linux-x64 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Audio/Ryujinx.Audio.csproj b/src/Ryujinx.Audio/Ryujinx.Audio.csproj index fc20f4ec4..8901bbf59 100644 --- a/src/Ryujinx.Audio/Ryujinx.Audio.csproj +++ b/src/Ryujinx.Audio/Ryujinx.Audio.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Common/Configuration/Hid/Controller/JoyconConfigControllerStick.cs b/src/Ryujinx.Common/Configuration/Hid/Controller/JoyconConfigControllerStick.cs index 608681551..076530744 100644 --- a/src/Ryujinx.Common/Configuration/Hid/Controller/JoyconConfigControllerStick.cs +++ b/src/Ryujinx.Common/Configuration/Hid/Controller/JoyconConfigControllerStick.cs @@ -1,6 +1,8 @@ namespace Ryujinx.Common.Configuration.Hid.Controller { - public class JoyconConfigControllerStick where TButton : unmanaged where TStick : unmanaged + public class JoyconConfigControllerStick + where TButton : unmanaged + where TStick : unmanaged { public TStick Joystick { get; set; } public bool InvertStickX { get; set; } diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs index 0cb49ca8c..6b8152b9d 100644 --- a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs +++ b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs @@ -2,7 +2,7 @@ namespace Ryujinx.Common.Configuration.Hid { public class KeyboardHotkeys { - public Key ToggleVsync { get; set; } + public Key ToggleVSyncMode { get; set; } public Key Screenshot { get; set; } public Key ShowUI { get; set; } public Key Pause { get; set; } @@ -11,5 +11,7 @@ namespace Ryujinx.Common.Configuration.Hid public Key ResScaleDown { get; set; } public Key VolumeUp { get; set; } public Key VolumeDown { get; set; } + public Key CustomVSyncIntervalIncrement { get; set; } + public Key CustomVSyncIntervalDecrement { get; set; } } } diff --git a/src/Ryujinx.Common/Configuration/VSyncMode.cs b/src/Ryujinx.Common/Configuration/VSyncMode.cs new file mode 100644 index 000000000..ca93b5e1c --- /dev/null +++ b/src/Ryujinx.Common/Configuration/VSyncMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Common.Configuration +{ + public enum VSyncMode + { + Switch, + Unbounded, + Custom + } +} diff --git a/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs b/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs index 631df3056..94e9359c8 100644 --- a/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs +++ b/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs @@ -69,9 +69,10 @@ namespace Ryujinx.Common.Logging.Targets } string version = ReleaseInformation.Version; + string appName = ReleaseInformation.IsCanaryBuild ? "Ryujinx_Canary" : "Ryujinx"; // Get path for the current time - path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"); + path = Path.Combine(logDir.FullName, $"{appName}_{version}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"); try { diff --git a/src/Ryujinx.Common/ReleaseInformation.cs b/src/Ryujinx.Common/ReleaseInformation.cs index f4c62155a..011d9848a 100644 --- a/src/Ryujinx.Common/ReleaseInformation.cs +++ b/src/Ryujinx.Common/ReleaseInformation.cs @@ -1,3 +1,4 @@ +using System; using System.Reflection; namespace Ryujinx.Common @@ -35,5 +36,13 @@ namespace Ryujinx.Common public static bool IsReleaseBuild => IsValid && ReleaseChannelName.Equals(ReleaseChannel); public static string Version => IsValid ? BuildVersion : Assembly.GetEntryAssembly()!.GetCustomAttribute()?.InformationalVersion; + + public static string GetChangelogUrl(Version currentVersion, Version newVersion) => + IsCanaryBuild + ? $"https://github.com/{ReleaseChannelOwner}/{ReleaseChannelSourceRepo}/compare/Canary-{currentVersion}...Canary-{newVersion}" + : $"https://github.com/{ReleaseChannelOwner}/{ReleaseChannelSourceRepo}/releases/tag/{newVersion}"; + + public static string GetChangelogForVersion(Version version) => + $"https://github.com/{ReleaseChannelOwner}/{ReleaseChannelRepo}/releases/tag/{version}"; } } diff --git a/src/Ryujinx.Common/Ryujinx.Common.csproj b/src/Ryujinx.Common/Ryujinx.Common.csproj index dee462fdb..85d4b58bd 100644 --- a/src/Ryujinx.Common/Ryujinx.Common.csproj +++ b/src/Ryujinx.Common/Ryujinx.Common.csproj @@ -4,6 +4,7 @@ net8.0 true $(DefineConstants);$(ExtraDefineConstants) + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Cpu/AddressTable.cs b/src/Ryujinx.Cpu/AddressTable.cs new file mode 100644 index 000000000..038a2009c --- /dev/null +++ b/src/Ryujinx.Cpu/AddressTable.cs @@ -0,0 +1,482 @@ +using ARMeilleure.Memory; +using Ryujinx.Common; +using Ryujinx.Cpu.Signal; +using Ryujinx.Memory; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using static Ryujinx.Cpu.MemoryEhMeilleure; + +namespace ARMeilleure.Common +{ + /// + /// Represents a table of guest address to a value. + /// + /// Type of the value + public unsafe class AddressTable : IAddressTable where TEntry : unmanaged + { + /// + /// Represents a page of the address table. + /// + private readonly struct AddressTablePage + { + /// + /// True if the allocation belongs to a sparse block, false otherwise. + /// + public readonly bool IsSparse; + + /// + /// Base address for the page. + /// + public readonly IntPtr Address; + + public AddressTablePage(bool isSparse, IntPtr address) + { + IsSparse = isSparse; + Address = address; + } + } + + /// + /// A sparsely mapped block of memory with a signal handler to map pages as they're accessed. + /// + private readonly struct TableSparseBlock : IDisposable + { + public readonly SparseMemoryBlock Block; + private readonly TrackingEventDelegate _trackingEvent; + + public TableSparseBlock(ulong size, Action ensureMapped, PageInitDelegate pageInit) + { + var block = new SparseMemoryBlock(size, pageInit, null); + + _trackingEvent = (ulong address, ulong size, bool write) => + { + ulong pointer = (ulong)block.Block.Pointer + address; + ensureMapped((IntPtr)pointer); + return pointer; + }; + + bool added = NativeSignalHandler.AddTrackedRegion( + (nuint)block.Block.Pointer, + (nuint)(block.Block.Pointer + (IntPtr)block.Block.Size), + Marshal.GetFunctionPointerForDelegate(_trackingEvent)); + + if (!added) + { + throw new InvalidOperationException("Number of allowed tracked regions exceeded."); + } + + Block = block; + } + + public void Dispose() + { + NativeSignalHandler.RemoveTrackedRegion((nuint)Block.Block.Pointer); + + Block.Dispose(); + } + } + + private bool _disposed; + private TEntry** _table; + private readonly List _pages; + private TEntry _fill; + + private readonly MemoryBlock _sparseFill; + private readonly SparseMemoryBlock _fillBottomLevel; + private readonly TEntry* _fillBottomLevelPtr; + + private readonly List _sparseReserved; + private readonly ReaderWriterLockSlim _sparseLock; + + private ulong _sparseBlockSize; + private ulong _sparseReservedOffset; + + public bool Sparse { get; } + + /// + public ulong Mask { get; } + + /// + public AddressTableLevel[] Levels { get; } + + /// + public TEntry Fill + { + get + { + return _fill; + } + set + { + UpdateFill(value); + } + } + + /// + public IntPtr Base + { + get + { + ObjectDisposedException.ThrowIf(_disposed, this); + + lock (_pages) + { + return (IntPtr)GetRootPage(); + } + } + } + + /// + /// Constructs a new instance of the class with the specified list of + /// . + /// + /// Levels for the address table + /// True if the bottom page should be sparsely mapped + /// is null + /// Length of is less than 2 + public AddressTable(AddressTableLevel[] levels, bool sparse) + { + ArgumentNullException.ThrowIfNull(levels); + + _pages = new List(capacity: 16); + + Levels = levels; + Mask = 0; + + foreach (var level in Levels) + { + Mask |= level.Mask; + } + + Sparse = sparse; + + if (sparse) + { + // If the address table is sparse, allocate a fill block + + _sparseFill = new MemoryBlock(268435456ul, MemoryAllocationFlags.Mirrorable); //low Power TC uses size: 65536ul + + ulong bottomLevelSize = (1ul << levels.Last().Length) * (ulong)sizeof(TEntry); + + _fillBottomLevel = new SparseMemoryBlock(bottomLevelSize, null, _sparseFill); + _fillBottomLevelPtr = (TEntry*)_fillBottomLevel.Block.Pointer; + + _sparseReserved = new List(); + _sparseLock = new ReaderWriterLockSlim(); + + _sparseBlockSize = bottomLevelSize; + } + } + + /// + /// Create an instance for an ARM function table. + /// Selects the best table structure for A32/A64, taking into account the selected memory manager type. + /// + /// True if the guest is A64, false otherwise + /// Memory manager type + /// An for ARM function lookup + public static AddressTable CreateForArm(bool for64Bits, MemoryManagerType type) + { + // Assume software memory means that we don't want to use any signal handlers. + bool sparse = type != MemoryManagerType.SoftwareMmu && type != MemoryManagerType.SoftwarePageTable; + + return new AddressTable(AddressTablePresets.GetArmPreset(for64Bits, sparse), sparse); + } + + /// + /// Update the fill value for the bottom level of the table. + /// + /// New fill value + private void UpdateFill(TEntry fillValue) + { + if (_sparseFill != null) + { + Span span = _sparseFill.GetSpan(0, (int)_sparseFill.Size); + MemoryMarshal.Cast(span).Fill(fillValue); + } + + _fill = fillValue; + } + + /// + /// Signal that the given code range exists. + /// + /// + /// + public void SignalCodeRange(ulong address, ulong size) + { + AddressTableLevel bottom = Levels.Last(); + ulong bottomLevelEntries = 1ul << bottom.Length; + + ulong entryIndex = address >> bottom.Index; + ulong entries = size >> bottom.Index; + entries += entryIndex - BitUtils.AlignDown(entryIndex, bottomLevelEntries); + + _sparseBlockSize = Math.Max(_sparseBlockSize, BitUtils.AlignUp(entries, bottomLevelEntries) * (ulong)sizeof(TEntry)); + } + + /// + public bool IsValid(ulong address) + { + return (address & ~Mask) == 0; + } + + /// + public ref TEntry GetValue(ulong address) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + if (!IsValid(address)) + { + throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address)); + } + + lock (_pages) + { + TEntry* page = GetPage(address); + + long index = Levels[^1].GetValue(address); + + EnsureMapped((IntPtr)(page + index)); + + return ref page[index]; + } + } + + /// + /// Gets the leaf page for the specified guest . + /// + /// Guest address + /// Leaf page for the specified guest + private TEntry* GetPage(ulong address) + { + TEntry** page = GetRootPage(); + + for (int i = 0; i < Levels.Length - 1; i++) + { + ref AddressTableLevel level = ref Levels[i]; + ref TEntry* nextPage = ref page[level.GetValue(address)]; + + if (nextPage == null || nextPage == _fillBottomLevelPtr) + { + ref AddressTableLevel nextLevel = ref Levels[i + 1]; + + if (i == Levels.Length - 2) + { + nextPage = (TEntry*)Allocate(1 << nextLevel.Length, Fill, leaf: true); + } + else + { + nextPage = (TEntry*)Allocate(1 << nextLevel.Length, GetFillValue(i), leaf: false); + } + } + + page = (TEntry**)nextPage; + } + + return (TEntry*)page; + } + + /// + /// Ensure the given pointer is mapped in any overlapping sparse reservations. + /// + /// Pointer to be mapped + private void EnsureMapped(IntPtr ptr) + { + if (Sparse) + { + // Check sparse allocations to see if the pointer is in any of them. + // Ensure the page is committed if there's a match. + + _sparseLock.EnterReadLock(); + + try + { + foreach (TableSparseBlock reserved in _sparseReserved) + { + SparseMemoryBlock sparse = reserved.Block; + + if (ptr >= sparse.Block.Pointer && ptr < sparse.Block.Pointer + (IntPtr)sparse.Block.Size) + { + sparse.EnsureMapped((ulong)(ptr - sparse.Block.Pointer)); + + break; + } + } + } + finally + { + _sparseLock.ExitReadLock(); + } + } + } + + /// + /// Get the fill value for a non-leaf level of the table. + /// + /// Level to get the fill value for + /// The fill value + private IntPtr GetFillValue(int level) + { + if (_fillBottomLevel != null && level == Levels.Length - 2) + { + return (IntPtr)_fillBottomLevelPtr; + } + else + { + return IntPtr.Zero; + } + } + + /// + /// Lazily initialize and get the root page of the . + /// + /// Root page of the + private TEntry** GetRootPage() + { + if (_table == null) + { + if (Levels.Length == 1) + _table = (TEntry**)Allocate(1 << Levels[0].Length, Fill, leaf: true); + else + _table = (TEntry**)Allocate(1 << Levels[0].Length, GetFillValue(0), leaf: false); + } + + return _table; + } + + /// + /// Initialize a leaf page with the fill value. + /// + /// Page to initialize + private void InitLeafPage(Span page) + { + MemoryMarshal.Cast(page).Fill(_fill); + } + + /// + /// Reserve a new sparse block, and add it to the list. + /// + /// The new sparse block that was added + private TableSparseBlock ReserveNewSparseBlock() + { + var block = new TableSparseBlock(_sparseBlockSize, EnsureMapped, InitLeafPage); + + _sparseReserved.Add(block); + _sparseReservedOffset = 0; + + return block; + } + + /// + /// Allocates a block of memory of the specified type and length. + /// + /// Type of elements + /// Number of elements + /// Fill value + /// if leaf; otherwise + /// Allocated block + private IntPtr Allocate(int length, T fill, bool leaf) where T : unmanaged + { + var size = sizeof(T) * length; + + AddressTablePage page; + + if (Sparse && leaf) + { + _sparseLock.EnterWriteLock(); + + SparseMemoryBlock block; + + if (_sparseReserved.Count == 0) + { + block = ReserveNewSparseBlock().Block; + } + else + { + block = _sparseReserved.Last().Block; + + if (_sparseReservedOffset == block.Block.Size) + { + block = ReserveNewSparseBlock().Block; + } + } + + page = new AddressTablePage(true, block.Block.Pointer + (IntPtr)_sparseReservedOffset); + + _sparseReservedOffset += (ulong)size; + + _sparseLock.ExitWriteLock(); + } + else + { + var address = (IntPtr)NativeAllocator.Instance.Allocate((uint)size); + page = new AddressTablePage(false, address); + + var span = new Span((void*)page.Address, length); + span.Fill(fill); + } + + _pages.Add(page); + + //TranslatorEventSource.Log.AddressTableAllocated(size, leaf); + + return page.Address; + } + + /// + /// Releases all resources used by the instance. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases all unmanaged and optionally managed resources used by the + /// instance. + /// + /// to dispose managed resources also; otherwise just unmanaged resouces + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + foreach (var page in _pages) + { + if (!page.IsSparse) + { + Marshal.FreeHGlobal(page.Address); + } + } + + if (Sparse) + { + foreach (TableSparseBlock block in _sparseReserved) + { + block.Dispose(); + } + + _sparseReserved.Clear(); + + _fillBottomLevel.Dispose(); + _sparseFill.Dispose(); + _sparseLock.Dispose(); + } + + _disposed = true; + } + } + + /// + /// Frees resources used by the instance. + /// + ~AddressTable() + { + Dispose(false); + } + } +} diff --git a/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs b/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs index 99e4c0479..784949441 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs @@ -32,7 +32,7 @@ namespace Ryujinx.Cpu.AppleHv { } - public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) + public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector) { return new DummyDiskCacheLoadState(); } diff --git a/src/Ryujinx.Cpu/ICpuContext.cs b/src/Ryujinx.Cpu/ICpuContext.cs index edcebdfc4..1fb3b674d 100644 --- a/src/Ryujinx.Cpu/ICpuContext.cs +++ b/src/Ryujinx.Cpu/ICpuContext.cs @@ -48,7 +48,7 @@ namespace Ryujinx.Cpu /// Version of the application /// True if the cache should be loaded from disk if it exists, false otherwise /// Disk cache load progress reporter and manager - IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled); + IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector); /// /// Indicates that code has been loaded into guest memory, and that it might be executed in the future. diff --git a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs index 9893c59b2..0793f382d 100644 --- a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs +++ b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs @@ -1,3 +1,4 @@ +using ARMeilleure.Common; using ARMeilleure.Memory; using ARMeilleure.Translation; using Ryujinx.Cpu.Signal; @@ -9,11 +10,13 @@ namespace Ryujinx.Cpu.Jit { private readonly ITickSource _tickSource; private readonly Translator _translator; + private readonly AddressTable _functionTable; public JitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit) { _tickSource = tickSource; - _translator = new Translator(new JitMemoryAllocator(forJit: true), memory, for64Bit); + _functionTable = AddressTable.CreateForArm(for64Bit, memory.Type); + _translator = new Translator(new JitMemoryAllocator(forJit: true), memory, _functionTable); if (memory.Type.IsHostMappedOrTracked()) { @@ -47,14 +50,15 @@ namespace Ryujinx.Cpu.Jit } /// - public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) + public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector) { - return new JitDiskCacheLoadState(_translator.LoadDiskCache(titleIdText, displayVersion, enabled)); + return new JitDiskCacheLoadState(_translator.LoadDiskCache(titleIdText, displayVersion, enabled, cacheSelector)); } /// public void PrepareCodeRange(ulong address, ulong size) { + _functionTable.SignalCodeRange(address, size); _translator.PrepareCodeRange(address, size); } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs index 7f5e4835c..48bdbb573 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs @@ -140,6 +140,10 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 bool isTail = false) { int tempRegister; + int tempGuestAddress = -1; + + bool inlineLookup = guestAddress.Kind != OperandKind.Constant && + funcTable is { Sparse: true }; if (guestAddress.Kind == OperandKind.Constant) { @@ -153,9 +157,16 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 else { asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset); + + if (inlineLookup && guestAddress.Value == 0) + { + // X0 will be overwritten. Move the address to a temp register. + tempGuestAddress = regAlloc.AllocateTempGprRegister(); + asm.Mov(Register(tempGuestAddress), guestAddress); + } } - tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1; + tempRegister = NextFreeRegister(1, tempGuestAddress); if (!isTail) { @@ -176,6 +187,40 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 asm.Mov(rn, funcPtrLoc & ~0xfffUL); asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL)); } + else if (inlineLookup) + { + // Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels. + + Operand indexReg = Register(NextFreeRegister(tempRegister + 1, tempGuestAddress)); + + if (tempGuestAddress != -1) + { + guestAddress = Register(tempGuestAddress); + } + + ulong tableBase = (ulong)funcTable.Base; + + // Index into the table. + asm.Mov(rn, tableBase); + + for (int i = 0; i < funcTable.Levels.Length; i++) + { + var level = funcTable.Levels[i]; + asm.Ubfx(indexReg, guestAddress, level.Index, level.Length); + asm.Lsl(indexReg, indexReg, Const(3)); + + // Index into the page. + asm.Add(rn, rn, indexReg); + + // Load the page address. + asm.LdrRiUn(rn, rn, 0); + } + + if (tempGuestAddress != -1) + { + regAlloc.FreeTempGprRegister(tempGuestAddress); + } + } else { asm.Mov(rn, (ulong)funcPtr); @@ -252,5 +297,20 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 { return new Operand(register, RegisterType.Integer, type); } + + private static Operand Const(long value, OperandType type = OperandType.I64) + { + return new Operand(type, (ulong)value); + } + + private static int NextFreeRegister(int start, int avoid) + { + if (start == avoid) + { + start++; + } + + return start; + } } } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs index 1eeeb746e..f534e8b6e 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs @@ -305,6 +305,10 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 bool isTail = false) { int tempRegister; + int tempGuestAddress = -1; + + bool inlineLookup = guestAddress.Kind != OperandKind.Constant && + funcTable is { Sparse: true }; if (guestAddress.Kind == OperandKind.Constant) { @@ -318,9 +322,16 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 else { asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset); + + if (inlineLookup && guestAddress.Value == 0) + { + // X0 will be overwritten. Move the address to a temp register. + tempGuestAddress = regAlloc.AllocateTempGprRegister(); + asm.Mov(Register(tempGuestAddress), guestAddress); + } } - tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1; + tempRegister = NextFreeRegister(1, tempGuestAddress); if (!isTail) { @@ -341,6 +352,40 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 asm.Mov(rn, funcPtrLoc & ~0xfffUL); asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL)); } + else if (inlineLookup) + { + // Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels. + + Operand indexReg = Register(NextFreeRegister(tempRegister + 1, tempGuestAddress)); + + if (tempGuestAddress != -1) + { + guestAddress = Register(tempGuestAddress); + } + + ulong tableBase = (ulong)funcTable.Base; + + // Index into the table. + asm.Mov(rn, tableBase); + + for (int i = 0; i < funcTable.Levels.Length; i++) + { + var level = funcTable.Levels[i]; + asm.Ubfx(indexReg, guestAddress, level.Index, level.Length); + asm.Lsl(indexReg, indexReg, Const(3)); + + // Index into the page. + asm.Add(rn, rn, indexReg); + + // Load the page address. + asm.LdrRiUn(rn, rn, 0); + } + + if (tempGuestAddress != -1) + { + regAlloc.FreeTempGprRegister(tempGuestAddress); + } + } else { asm.Mov(rn, (ulong)funcPtr); @@ -613,5 +658,20 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 { return new Operand(register, RegisterType.Integer, type); } + + private static Operand Const(long value, OperandType type = OperandType.I64) + { + return new Operand(type, (ulong)value); + } + + private static int NextFreeRegister(int start, int avoid) + { + if (start == avoid) + { + start++; + } + + return start; + } } } diff --git a/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs b/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs index b63636e39..0f47ffb15 100644 --- a/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs +++ b/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs @@ -1,3 +1,4 @@ +using ARMeilleure.Common; using ARMeilleure.Memory; using Ryujinx.Cpu.Jit; using Ryujinx.Cpu.LightningJit.State; @@ -8,11 +9,16 @@ namespace Ryujinx.Cpu.LightningJit { private readonly ITickSource _tickSource; private readonly Translator _translator; + private readonly AddressTable _functionTable; public LightningJitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit) { _tickSource = tickSource; - _translator = new Translator(memory, for64Bit); + + _functionTable = AddressTable.CreateForArm(for64Bit, memory.Type); + + _translator = new Translator(memory, _functionTable); + memory.UnmapEvent += UnmapHandler; } @@ -40,7 +46,7 @@ namespace Ryujinx.Cpu.LightningJit } /// - public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) + public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector) { return new DummyDiskCacheLoadState(); } @@ -48,6 +54,7 @@ namespace Ryujinx.Cpu.LightningJit /// public void PrepareCodeRange(ulong address, ulong size) { + _functionTable.SignalCodeRange(address, size); } public void Dispose() diff --git a/src/Ryujinx.Cpu/LightningJit/Translator.cs b/src/Ryujinx.Cpu/LightningJit/Translator.cs index b4710e34e..4c4011f11 100644 --- a/src/Ryujinx.Cpu/LightningJit/Translator.cs +++ b/src/Ryujinx.Cpu/LightningJit/Translator.cs @@ -19,25 +19,6 @@ namespace Ryujinx.Cpu.LightningJit // Should be enabled on platforms that enforce W^X. private static bool IsNoWxPlatform => false; - private static readonly AddressTable.Level[] _levels64Bit = - new AddressTable.Level[] - { - new(31, 17), - new(23, 8), - new(15, 8), - new( 7, 8), - new( 2, 5), - }; - - private static readonly AddressTable.Level[] _levels32Bit = - new AddressTable.Level[] - { - new(23, 9), - new(15, 8), - new( 7, 8), - new( 1, 6), - }; - private readonly ConcurrentQueue> _oldFuncs; private readonly NoWxCache _noWxCache; private bool _disposed; @@ -47,7 +28,7 @@ namespace Ryujinx.Cpu.LightningJit internal TranslatorStubs Stubs { get; } internal IMemoryManager Memory { get; } - public Translator(IMemoryManager memory, bool for64Bits) + public Translator(IMemoryManager memory, AddressTable functionTable) { Memory = memory; @@ -63,7 +44,7 @@ namespace Ryujinx.Cpu.LightningJit } Functions = new TranslatorCache(); - FunctionTable = new AddressTable(for64Bits ? _levels64Bit : _levels32Bit); + FunctionTable = functionTable; Stubs = new TranslatorStubs(FunctionTable, _noWxCache); FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub; diff --git a/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs b/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs index e88414d5e..c5231e506 100644 --- a/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs +++ b/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs @@ -23,7 +23,7 @@ namespace Ryujinx.Cpu.LightningJit private bool _disposed; - private readonly AddressTable _functionTable; + private readonly IAddressTable _functionTable; private readonly NoWxCache _noWxCache; private readonly GetFunctionAddressDelegate _getFunctionAddressRef; private readonly nint _getFunctionAddress; @@ -79,7 +79,7 @@ namespace Ryujinx.Cpu.LightningJit /// Function table used to store pointers to the functions that the guest code will call /// Cache used on platforms that enforce W^X, otherwise should be null /// is null - public TranslatorStubs(AddressTable functionTable, NoWxCache noWxCache) + public TranslatorStubs(IAddressTable functionTable, NoWxCache noWxCache) { ArgumentNullException.ThrowIfNull(functionTable); diff --git a/src/Ryujinx.Cpu/Ryujinx.Cpu.csproj b/src/Ryujinx.Cpu/Ryujinx.Cpu.csproj index 5a6bf5c3d..0a55a7dea 100644 --- a/src/Ryujinx.Cpu/Ryujinx.Cpu.csproj +++ b/src/Ryujinx.Cpu/Ryujinx.Cpu.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj b/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj index 973a9e260..58f54de7d 100644 --- a/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj +++ b/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.GAL/IWindow.cs b/src/Ryujinx.Graphics.GAL/IWindow.cs index 83418e709..12686cb28 100644 --- a/src/Ryujinx.Graphics.GAL/IWindow.cs +++ b/src/Ryujinx.Graphics.GAL/IWindow.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.GAL void SetSize(int width, int height); - void ChangeVSyncMode(bool vsyncEnabled); + void ChangeVSyncMode(VSyncMode vSyncMode); void SetAntiAliasing(AntiAliasing antialiasing); void SetScalingFilter(ScalingFilter type); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs index acda37ef3..102fdb1bb 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading _impl.Window.SetSize(width, height); } - public void ChangeVSyncMode(bool vsyncEnabled) { } + public void ChangeVSyncMode(VSyncMode vSyncMode) { } public void SetAntiAliasing(AntiAliasing effect) { } diff --git a/src/Ryujinx.Graphics.GAL/Ryujinx.Graphics.GAL.csproj b/src/Ryujinx.Graphics.GAL/Ryujinx.Graphics.GAL.csproj index d88b641a3..a230296c1 100644 --- a/src/Ryujinx.Graphics.GAL/Ryujinx.Graphics.GAL.csproj +++ b/src/Ryujinx.Graphics.GAL/Ryujinx.Graphics.GAL.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.GAL/VSyncMode.cs b/src/Ryujinx.Graphics.GAL/VSyncMode.cs new file mode 100644 index 000000000..c5794b8f7 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/VSyncMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Graphics.GAL +{ + public enum VSyncMode + { + Switch, + Unbounded, + Custom + } +} diff --git a/src/Ryujinx.Graphics.Gpu/Ryujinx.Graphics.Gpu.csproj b/src/Ryujinx.Graphics.Gpu/Ryujinx.Graphics.Gpu.csproj index 6f1cce6ac..8c740fadc 100644 --- a/src/Ryujinx.Graphics.Gpu/Ryujinx.Graphics.Gpu.csproj +++ b/src/Ryujinx.Graphics.Gpu/Ryujinx.Graphics.Gpu.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj b/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj index d631d039f..92077e26a 100644 --- a/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj +++ b/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Nvdec.FFmpeg/Ryujinx.Graphics.Nvdec.FFmpeg.csproj b/src/Ryujinx.Graphics.Nvdec.FFmpeg/Ryujinx.Graphics.Nvdec.FFmpeg.csproj index d1a6358c2..7659c4b25 100644 --- a/src/Ryujinx.Graphics.Nvdec.FFmpeg/Ryujinx.Graphics.Nvdec.FFmpeg.csproj +++ b/src/Ryujinx.Graphics.Nvdec.FFmpeg/Ryujinx.Graphics.Nvdec.FFmpeg.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Nvdec.Vp9/Ryujinx.Graphics.Nvdec.Vp9.csproj b/src/Ryujinx.Graphics.Nvdec.Vp9/Ryujinx.Graphics.Nvdec.Vp9.csproj index d1a6358c2..7659c4b25 100644 --- a/src/Ryujinx.Graphics.Nvdec.Vp9/Ryujinx.Graphics.Nvdec.Vp9.csproj +++ b/src/Ryujinx.Graphics.Nvdec.Vp9/Ryujinx.Graphics.Nvdec.Vp9.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj b/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj index 6c00e9a7c..7a13b5d1b 100644 --- a/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj +++ b/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj b/src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj index f3071f486..931e70c03 100644 --- a/src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj +++ b/src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.OpenGL/Window.cs b/src/Ryujinx.Graphics.OpenGL/Window.cs index 285ab725e..1dc8a51f6 100644 --- a/src/Ryujinx.Graphics.OpenGL/Window.cs +++ b/src/Ryujinx.Graphics.OpenGL/Window.cs @@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.OpenGL GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4); } - public void ChangeVSyncMode(bool vsyncEnabled) { } + public void ChangeVSyncMode(VSyncMode vSyncMode) { } public void SetSize(int width, int height) { diff --git a/src/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj b/src/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj index 8ccf5348f..be32641eb 100644 --- a/src/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj +++ b/src/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Texture/Ryujinx.Graphics.Texture.csproj b/src/Ryujinx.Graphics.Texture/Ryujinx.Graphics.Texture.csproj index 51721490e..48d10f1d5 100644 --- a/src/Ryujinx.Graphics.Texture/Ryujinx.Graphics.Texture.csproj +++ b/src/Ryujinx.Graphics.Texture/Ryujinx.Graphics.Texture.csproj @@ -2,6 +2,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj index a6c4fb2bb..820e807e6 100644 --- a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj +++ b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Video/Ryujinx.Graphics.Video.csproj b/src/Ryujinx.Graphics.Video/Ryujinx.Graphics.Video.csproj index abff58a53..d85effe32 100644 --- a/src/Ryujinx.Graphics.Video/Ryujinx.Graphics.Video.csproj +++ b/src/Ryujinx.Graphics.Video/Ryujinx.Graphics.Video.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj b/src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj index aae28733f..b138e309a 100644 --- a/src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj +++ b/src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index c9aab4018..436914330 100644 --- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -182,6 +182,16 @@ namespace Ryujinx.Graphics.Vulkan return false; } } + + //Prevent the sum of descriptors from exceeding MaxPushDescriptors + int totalDescriptors = 0; + foreach (ResourceDescriptor desc in layout.Sets.First().Descriptors) + { + if (!reserved.Contains(desc.Binding)) + totalDescriptors += desc.Count; + } + if (totalDescriptors > gd.Capabilities.MaxPushDescriptors) + return false; return true; } diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index 3dc6d4e19..3e8d3b375 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Vulkan private int _width; private int _height; - private bool _vsyncEnabled; + private VSyncMode _vSyncMode; private bool _swapchainIsDirty; private VkFormat _format; private AntiAliasing _currentAntiAliasing; @@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.Vulkan ImageArrayLayers = 1, PreTransform = capabilities.CurrentTransform, CompositeAlpha = ChooseCompositeAlpha(capabilities.SupportedCompositeAlpha), - PresentMode = ChooseSwapPresentMode(presentModes, _vsyncEnabled), + PresentMode = ChooseSwapPresentMode(presentModes, _vSyncMode), Clipped = true, }; @@ -279,9 +279,9 @@ namespace Ryujinx.Graphics.Vulkan } } - private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, bool vsyncEnabled) + private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, VSyncMode vSyncMode) { - if (!vsyncEnabled && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr)) + if (vSyncMode == VSyncMode.Unbounded && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr)) { return PresentModeKHR.ImmediateKhr; } @@ -634,9 +634,10 @@ namespace Ryujinx.Graphics.Vulkan _swapchainIsDirty = true; } - public override void ChangeVSyncMode(bool vsyncEnabled) + public override void ChangeVSyncMode(VSyncMode vSyncMode) { - _vsyncEnabled = vsyncEnabled; + _vSyncMode = vSyncMode; + //present mode may change, so mark the swapchain for recreation _swapchainIsDirty = true; } diff --git a/src/Ryujinx.Graphics.Vulkan/WindowBase.cs b/src/Ryujinx.Graphics.Vulkan/WindowBase.cs index edb9c688c..ca06ec0b8 100644 --- a/src/Ryujinx.Graphics.Vulkan/WindowBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/WindowBase.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Vulkan public abstract void Dispose(); public abstract void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback); public abstract void SetSize(int width, int height); - public abstract void ChangeVSyncMode(bool vsyncEnabled); + public abstract void ChangeVSyncMode(VSyncMode vSyncMode); public abstract void SetAntiAliasing(AntiAliasing effect); public abstract void SetScalingFilter(ScalingFilter scalerType); public abstract void SetScalingFilterLevel(float scale); diff --git a/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj b/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj index eeab9c0e9..4791a3b27 100644 --- a/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj +++ b/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj @@ -6,6 +6,7 @@ true Generated true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index fc8def9d2..51f6058fc 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -21,6 +21,7 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using Path = System.IO.Path; namespace Ryujinx.HLE.FileSystem @@ -474,6 +475,74 @@ namespace Ryujinx.HLE.FileSystem FinishInstallation(temporaryDirectory, registeredDirectory); } + public void InstallKeys(string keysSource, string installDirectory) + { + if (Directory.Exists(keysSource)) + { + foreach (var filePath in Directory.EnumerateFiles(keysSource, "*.keys")) + { + VerifyKeysFile(filePath); + File.Copy(filePath, Path.Combine(installDirectory, Path.GetFileName(filePath)), true); + } + + return; + } + + if (!File.Exists(keysSource)) + { + throw new FileNotFoundException("Keys file does not exist."); + } + + FileInfo info = new(keysSource); + + using FileStream file = File.OpenRead(keysSource); + + switch (info.Extension) + { + case ".zip": + using (ZipArchive archive = ZipFile.OpenRead(keysSource)) + { + InstallKeysFromZip(archive, installDirectory); + } + break; + case ".keys": + VerifyKeysFile(keysSource); + File.Copy(keysSource, Path.Combine(installDirectory, info.Name), true); + break; + default: + throw new InvalidFirmwarePackageException("Input file is not a valid key package"); + } + } + + private void InstallKeysFromZip(ZipArchive archive, string installDirectory) + { + string temporaryDirectory = Path.Combine(installDirectory, "temp"); + if (Directory.Exists(temporaryDirectory)) + { + Directory.Delete(temporaryDirectory, true); + } + Directory.CreateDirectory(temporaryDirectory); + foreach (var entry in archive.Entries) + { + if (Path.GetExtension(entry.FullName).Equals(".keys", StringComparison.OrdinalIgnoreCase)) + { + string extractDestination = Path.Combine(temporaryDirectory, entry.Name); + entry.ExtractToFile(extractDestination, overwrite: true); + try + { + VerifyKeysFile(extractDestination); + File.Move(extractDestination, Path.Combine(installDirectory, entry.Name), true); + } + catch (Exception) + { + Directory.Delete(temporaryDirectory, true); + throw; + } + } + } + Directory.Delete(temporaryDirectory, true); + } + private void FinishInstallation(string temporaryDirectory, string registeredDirectory) { if (Directory.Exists(registeredDirectory)) @@ -947,5 +1016,70 @@ namespace Ryujinx.HLE.FileSystem return null; } + + public void VerifyKeysFile(string filePath) + { + // Verify the keys file format refers to https://github.com/Thealexbarney/LibHac/blob/master/KEYS.md + string genericPattern = @"^[a-z0-9_]+ = [a-z0-9]+$"; + string titlePattern = @"^[a-z0-9]{32} = [a-z0-9]{32}$"; + + if (File.Exists(filePath)) + { + // Read all lines from the file + string fileName = Path.GetFileName(filePath); + string[] lines = File.ReadAllLines(filePath); + + bool verified = false; + switch (fileName) + { + case "prod.keys": + verified = verifyKeys(lines, genericPattern); + break; + case "title.keys": + verified = verifyKeys(lines, titlePattern); + break; + case "console.keys": + verified = verifyKeys(lines, genericPattern); + break; + case "dev.keys": + verified = verifyKeys(lines, genericPattern); + break; + default: + throw new FormatException($"Keys file name \"{fileName}\" not supported. Only \"prod.keys\", \"title.keys\", \"console.keys\", \"dev.keys\" are supported."); + } + if (!verified) + { + throw new FormatException($"Invalid \"{filePath}\" file format."); + } + } else + { + throw new FileNotFoundException($"Keys file not found at \"{filePath}\"."); + } + } + + private bool verifyKeys(string[] lines, string regex) + { + foreach (string line in lines) + { + if (!Regex.IsMatch(line, regex)) + { + return false; + } + } + return true; + } + + public bool AreKeysAlredyPresent(string pathToCheck) + { + string[] fileNames = { "prod.keys", "title.keys", "console.keys", "dev.keys" }; + foreach (var file in fileNames) + { + if (File.Exists(Path.Combine(pathToCheck, file))) + { + return true; + } + } + return false; + } } } diff --git a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index 39c544eac..ef9c493a8 100644 --- a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -223,9 +223,10 @@ namespace Ryujinx.HLE.FileSystem { KeySet ??= KeySet.CreateDefaultKeySet(); - string keyFile = null; + string prodKeyFile = null; string titleKeyFile = null; string consoleKeyFile = null; + string devKeyFile = null; if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile) { @@ -236,13 +237,14 @@ namespace Ryujinx.HLE.FileSystem void LoadSetAtPath(string basePath) { - string localKeyFile = Path.Combine(basePath, "prod.keys"); + string localProdKeyFile = Path.Combine(basePath, "prod.keys"); string localTitleKeyFile = Path.Combine(basePath, "title.keys"); string localConsoleKeyFile = Path.Combine(basePath, "console.keys"); + string localDevKeyFile = Path.Combine(basePath, "dev.keys"); - if (File.Exists(localKeyFile)) + if (File.Exists(localProdKeyFile)) { - keyFile = localKeyFile; + prodKeyFile = localProdKeyFile; } if (File.Exists(localTitleKeyFile)) @@ -254,9 +256,14 @@ namespace Ryujinx.HLE.FileSystem { consoleKeyFile = localConsoleKeyFile; } + + if (File.Exists(localDevKeyFile)) + { + devKeyFile = localDevKeyFile; + } } - ExternalKeyReader.ReadKeyFile(KeySet, keyFile, titleKeyFile, consoleKeyFile, null); + ExternalKeyReader.ReadKeyFile(KeySet, prodKeyFile, devKeyFile, titleKeyFile, consoleKeyFile, null); } public void ImportTickets(IFileSystem fs) diff --git a/src/Ryujinx.HLE/HLEConfiguration.cs b/src/Ryujinx.HLE/HLEConfiguration.cs index 70fcf278d..f75ead588 100644 --- a/src/Ryujinx.HLE/HLEConfiguration.cs +++ b/src/Ryujinx.HLE/HLEConfiguration.cs @@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.UI; using System; +using VSyncMode = Ryujinx.Common.Configuration.VSyncMode; namespace Ryujinx.HLE { @@ -84,9 +85,14 @@ namespace Ryujinx.HLE internal readonly RegionCode Region; /// - /// Control the initial state of the vertical sync in the SurfaceFlinger service. + /// Control the initial state of the present interval in the SurfaceFlinger service (previously Vsync). /// - internal readonly bool EnableVsync; + internal readonly VSyncMode VSyncMode; + + /// + /// Control the custom VSync interval, if enabled and active. + /// + internal readonly int CustomVSyncInterval; /// /// Control the initial state of the docked mode. @@ -195,7 +201,7 @@ namespace Ryujinx.HLE IHostUIHandler hostUIHandler, SystemLanguage systemLanguage, RegionCode region, - bool enableVsync, + VSyncMode vSyncMode, bool enableDockedMode, bool enablePtc, bool enableInternetAccess, @@ -212,7 +218,8 @@ namespace Ryujinx.HLE MultiplayerMode multiplayerMode, bool multiplayerDisableP2p, string multiplayerLdnPassphrase, - string multiplayerLdnServer) + string multiplayerLdnServer, + int customVSyncInterval) { VirtualFileSystem = virtualFileSystem; LibHacHorizonManager = libHacHorizonManager; @@ -225,7 +232,8 @@ namespace Ryujinx.HLE HostUIHandler = hostUIHandler; SystemLanguage = systemLanguage; Region = region; - EnableVsync = enableVsync; + VSyncMode = vSyncMode; + CustomVSyncInterval = customVSyncInterval; EnableDockedMode = enableDockedMode; EnablePtc = enablePtc; EnableInternetAccess = enableInternetAccess; diff --git a/src/Ryujinx.HLE/HOS/Applets/AppletManager.cs b/src/Ryujinx.HLE/HOS/Applets/AppletManager.cs index da4d2e51b..5895c67bb 100644 --- a/src/Ryujinx.HLE/HOS/Applets/AppletManager.cs +++ b/src/Ryujinx.HLE/HOS/Applets/AppletManager.cs @@ -1,5 +1,6 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Applets.Browser; +using Ryujinx.HLE.HOS.Applets.Cabinet; using Ryujinx.HLE.HOS.Applets.Dummy; using Ryujinx.HLE.HOS.Applets.Error; using Ryujinx.HLE.HOS.Services.Am.AppletAE; @@ -23,14 +24,14 @@ namespace Ryujinx.HLE.HOS.Applets case AppletId.SoftwareKeyboard: return new SoftwareKeyboardApplet(system); case AppletId.LibAppletWeb: - return new BrowserApplet(system); case AppletId.LibAppletShop: - return new BrowserApplet(system); case AppletId.LibAppletOff: - return new BrowserApplet(system); + return new BrowserApplet(); case AppletId.MiiEdit: Logger.Warning?.Print(LogClass.Application, $"Please use the MiiEdit inside File/Open Applet"); return new DummyApplet(system); + case AppletId.Cabinet: + return new CabinetApplet(system); } Logger.Warning?.Print(LogClass.Application, $"Applet {applet} not implemented!"); diff --git a/src/Ryujinx.HLE/HOS/Applets/Browser/BrowserApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Browser/BrowserApplet.cs index 6afbe4a72..c5f13dab3 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Browser/BrowserApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Browser/BrowserApplet.cs @@ -18,13 +18,6 @@ namespace Ryujinx.HLE.HOS.Applets.Browser private List _arguments; private ShimKind _shimKind; - public BrowserApplet(Horizon system) { } - - public ResultCode GetResult() - { - return ResultCode.Success; - } - public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession) { _normalSession = normalSession; diff --git a/src/Ryujinx.HLE/HOS/Applets/Cabinet/CabinetApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Cabinet/CabinetApplet.cs new file mode 100644 index 000000000..294b8d1f6 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Applets/Cabinet/CabinetApplet.cs @@ -0,0 +1,182 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Common.Memory; +using Ryujinx.HLE.HOS.Services.Am.AppletAE; +using Ryujinx.HLE.HOS.Services.Hid.HidServer; +using Ryujinx.HLE.HOS.Services.Hid; +using Ryujinx.HLE.HOS.Services.Nfc.Nfp; +using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.HLE.HOS.Applets.Cabinet +{ + internal unsafe class CabinetApplet : IApplet + { + private readonly Horizon _system; + private AppletSession _normalSession; + + public event EventHandler AppletStateChanged; + + public CabinetApplet(Horizon system) + { + _system = system; + } + + public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession) + { + _normalSession = normalSession; + + byte[] launchParams = _normalSession.Pop(); + byte[] startParamBytes = _normalSession.Pop(); + + StartParamForAmiiboSettings startParam = IApplet.ReadStruct(startParamBytes); + + Logger.Stub?.PrintStub(LogClass.ServiceAm, $"CabinetApplet Start Type: {startParam.Type}"); + + switch (startParam.Type) + { + case 0: + StartNicknameAndOwnerSettings(ref startParam); + break; + case 1: + case 3: + StartFormatter(ref startParam); + break; + default: + Logger.Error?.Print(LogClass.ServiceAm, $"Unknown AmiiboSettings type: {startParam.Type}"); + break; + } + + // Prepare the response + ReturnValueForAmiiboSettings returnValue = new() + { + AmiiboSettingsReturnFlag = (byte)AmiiboSettingsReturnFlag.HasRegisterInfo, + DeviceHandle = new DeviceHandle + { + Handle = 0 // Dummy device handle + }, + RegisterInfo = startParam.RegisterInfo + }; + + // Push the response + _normalSession.Push(BuildResponse(returnValue)); + AppletStateChanged?.Invoke(this, null); + + _system.ReturnFocus(); + + return ResultCode.Success; + } + + public ResultCode GetResult() + { + _system.Device.System.NfpDevices.RemoveAt(0); + return ResultCode.Success; + } + + private void StartFormatter(ref StartParamForAmiiboSettings startParam) + { + // Initialize RegisterInfo + startParam.RegisterInfo = new RegisterInfo(); + } + + private void StartNicknameAndOwnerSettings(ref StartParamForAmiiboSettings startParam) + { + _system.Device.UIHandler.DisplayCabinetDialog(out string newName); + byte[] nameBytes = Encoding.UTF8.GetBytes(newName); + Array41 nickName = new Array41(); + nameBytes.CopyTo(nickName.AsSpan()); + startParam.RegisterInfo.Nickname = nickName; + NfpDevice devicePlayer1 = new() + { + NpadIdType = NpadIdType.Player1, + Handle = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1), + State = NfpDeviceState.SearchingForTag, + }; + _system.Device.System.NfpDevices.Add(devicePlayer1); + _system.Device.UIHandler.DisplayCabinetMessageDialog(); + string amiiboId = string.Empty; + bool scanned = false; + while (!scanned) + { + for (int i = 0; i < _system.Device.System.NfpDevices.Count; i++) + { + if (_system.Device.System.NfpDevices[i].State == NfpDeviceState.TagFound) + { + amiiboId = _system.Device.System.NfpDevices[i].AmiiboId; + scanned = true; + } + } + } + VirtualAmiibo.UpdateNickName(amiiboId, newName); + } + + private static byte[] BuildResponse(ReturnValueForAmiiboSettings returnValue) + { + int size = Unsafe.SizeOf(); + byte[] bytes = new byte[size]; + + fixed (byte* bytesPtr = bytes) + { + Unsafe.Write(bytesPtr, returnValue); + } + + return bytes; + } + + #region Structs + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public unsafe struct TagInfo + { + public fixed byte Data[0x58]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public unsafe struct StartParamForAmiiboSettings + { + public byte ZeroValue; // Left at zero by sdknso + public byte Type; + public byte Flags; + public byte AmiiboSettingsStartParamOffset28; + public ulong AmiiboSettingsStartParam0; + + public TagInfo TagInfo; // Only enabled when flags bit 1 is set + public RegisterInfo RegisterInfo; // Only enabled when flags bit 2 is set + + public fixed byte StartParamExtraData[0x20]; + + public fixed byte Reserved[0x24]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public unsafe struct ReturnValueForAmiiboSettings + { + public byte AmiiboSettingsReturnFlag; + private byte Padding1; + private byte Padding2; + private byte Padding3; + public DeviceHandle DeviceHandle; + public TagInfo TagInfo; + public RegisterInfo RegisterInfo; + public fixed byte IgnoredBySdknso[0x24]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct DeviceHandle + { + public ulong Handle; + } + + public enum AmiiboSettingsReturnFlag : byte + { + Cancel = 0, + HasTagInfo = 2, + HasRegisterInfo = 4, + HasTagInfoAndRegisterInfo = 6 + } + + #endregion + } +} diff --git a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs index 5ec9d4b08..3a7b29ab5 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs @@ -117,11 +117,6 @@ namespace Ryujinx.HLE.HOS.Applets return ResultCode.Success; } - public ResultCode GetResult() - { - return ResultCode.Success; - } - private static byte[] BuildResponse(ControllerSupportResultInfo result) { using MemoryStream stream = MemoryStreamManager.Shared.GetStream(); diff --git a/src/Ryujinx.HLE/HOS/Applets/Dummy/DummyApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Dummy/DummyApplet.cs index 75df7a373..6b16aee7b 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Dummy/DummyApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Dummy/DummyApplet.cs @@ -11,11 +11,14 @@ namespace Ryujinx.HLE.HOS.Applets.Dummy { private readonly Horizon _system; private AppletSession _normalSession; + public event EventHandler AppletStateChanged; + public DummyApplet(Horizon system) { _system = system; } + public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession) { _normalSession = normalSession; @@ -24,10 +27,7 @@ namespace Ryujinx.HLE.HOS.Applets.Dummy _system.ReturnFocus(); return ResultCode.Success; } - private static T ReadStruct(byte[] data) where T : struct - { - return MemoryMarshal.Read(data.AsSpan()); - } + private static byte[] BuildResponse() { using MemoryStream stream = MemoryStreamManager.Shared.GetStream(); @@ -35,9 +35,5 @@ namespace Ryujinx.HLE.HOS.Applets.Dummy writer.Write((ulong)ResultCode.Success); return stream.ToArray(); } - public ResultCode GetResult() - { - return ResultCode.Success; - } } } diff --git a/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs index 87d88fc65..0e043cc45 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs @@ -203,10 +203,5 @@ namespace Ryujinx.HLE.HOS.Applets.Error _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber} (Details)", "\n" + detailsText, buttons.ToArray()); } } - - public ResultCode GetResult() - { - return ResultCode.Success; - } } } diff --git a/src/Ryujinx.HLE/HOS/Applets/IApplet.cs b/src/Ryujinx.HLE/HOS/Applets/IApplet.cs index bc5353841..4500b2f63 100644 --- a/src/Ryujinx.HLE/HOS/Applets/IApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/IApplet.cs @@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets ResultCode Start(AppletSession normalSession, AppletSession interactiveSession); - ResultCode GetResult(); + ResultCode GetResult() => ResultCode.Success; bool DrawTo(RenderingSurfaceInfo surfaceInfo, IVirtualMemoryManager destination, ulong position) => false; diff --git a/src/Ryujinx.HLE/HOS/Applets/PlayerSelect/PlayerSelectApplet.cs b/src/Ryujinx.HLE/HOS/Applets/PlayerSelect/PlayerSelectApplet.cs index ccc761ba1..05bddc76f 100644 --- a/src/Ryujinx.HLE/HOS/Applets/PlayerSelect/PlayerSelectApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/PlayerSelect/PlayerSelectApplet.cs @@ -37,11 +37,6 @@ namespace Ryujinx.HLE.HOS.Applets return ResultCode.Success; } - public ResultCode GetResult() - { - return ResultCode.Success; - } - private byte[] BuildResponse() { UserProfile currentUser = _system.AccountManager.LastOpenedUser; diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs index e04fc64fe..9ec202357 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs @@ -144,11 +144,6 @@ namespace Ryujinx.HLE.HOS.Applets } } - public ResultCode GetResult() - { - return ResultCode.Success; - } - private bool IsKeyboardActive() { return _backgroundState >= InlineKeyboardState.Appearing && _backgroundState < InlineKeyboardState.Disappearing; diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TRef.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TRef.cs index 32d9e68da..51571401f 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TRef.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TRef.cs @@ -2,7 +2,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard { /// /// Wraps a type in a class so it gets stored in the GC managed heap. This is used as communication mechanism - /// between classed that need to be disposed and, thus, can't share their references. + /// between classes that need to be disposed and, thus, can't share their references. /// /// The internal type. class TRef diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContext.cs b/src/Ryujinx.HLE/HOS/ArmProcessContext.cs index fde489ab7..09a721644 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContext.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContext.cs @@ -13,7 +13,8 @@ namespace Ryujinx.HLE.HOS string displayVersion, bool diskCacheEnabled, ulong codeAddress, - ulong codeSize); + ulong codeSize, + string cacheSelector); } class ArmProcessContext : IArmProcessContext where T : class, IVirtualMemoryManagerTracked, IMemoryManager @@ -67,10 +68,11 @@ namespace Ryujinx.HLE.HOS string displayVersion, bool diskCacheEnabled, ulong codeAddress, - ulong codeSize) + ulong codeSize, + string cacheSelector) { _cpuContext.PrepareCodeRange(codeAddress, codeSize); - return _cpuContext.LoadDiskCache(titleIdText, displayVersion, diskCacheEnabled); + return _cpuContext.LoadDiskCache(titleIdText, displayVersion, diskCacheEnabled, cacheSelector); } public void InvalidateCacheRegion(ulong address, ulong size) diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs index 6646826cb..14775fb1d 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs @@ -114,7 +114,7 @@ namespace Ryujinx.HLE.HOS } } - DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize); + DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize, "default"); //Ready for exefs profiles return processContext; } diff --git a/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/IServiceCreator.cs b/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/IServiceCreator.cs index 797a7a9bd..705e5f258 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/IServiceCreator.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/IServiceCreator.cs @@ -5,5 +5,23 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.Lp2p class IServiceCreator : IpcService { public IServiceCreator(ServiceCtx context) { } + + [CommandCmif(0)] + // CreateNetworkService(pid, u64, u32) -> object + public ResultCode CreateNetworkService(ServiceCtx context) + { + MakeObject(context, new ISfService(context)); + + return ResultCode.Success; + } + + [CommandCmif(8)] + // CreateNetworkServiceMonitor(pid, u64) -> object + public ResultCode CreateNetworkServiceMonitor(ServiceCtx context) + { + MakeObject(context, new ISfServiceMonitor(context)); + + return ResultCode.Success; + } } } diff --git a/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfService.cs b/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfService.cs new file mode 100644 index 000000000..8f9f0e3e4 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfService.cs @@ -0,0 +1,54 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Ldn.Lp2p +{ + class ISfService : IpcService + { + public ISfService(ServiceCtx context) { } + + [CommandCmif(0)] + // Initialize() + public ResultCode Initialize(ServiceCtx context) + { + context.ResponseData.Write(0); + + return ResultCode.Success; + } + + [CommandCmif(768)] + // CreateGroup(buffer) + public ResultCode SendToOtherGroup(ServiceCtx context) + { + Logger.Stub?.PrintStub(LogClass.ServiceLdn); + + return ResultCode.Success; + } + + [CommandCmif(1544)] + // RecvFromOtherGroup(u32, buffer) -> (nn::lp2p::MacAddress, u16, s16, u32, s32) + public ResultCode RecvFromOtherGroup(ServiceCtx context) + { + Logger.Stub?.PrintStub(LogClass.ServiceLdn); + + return ResultCode.Success; + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfServiceMonitor.cs b/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfServiceMonitor.cs new file mode 100644 index 000000000..d3a8bead2 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfServiceMonitor.cs @@ -0,0 +1,86 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Horizon.Common; +using System; + +namespace Ryujinx.HLE.HOS.Services.Ldn.Lp2p +{ + class ISfServiceMonitor : IpcService + { + private readonly KEvent _stateChangeEvent; + private readonly KEvent _jointEvent; + private int _stateChangeEventHandle = 0; + private int _jointEventHandle = 0; + + public ISfServiceMonitor(ServiceCtx context) + { + _stateChangeEvent = new KEvent(context.Device.System.KernelContext); + _jointEvent = new KEvent(context.Device.System.KernelContext); + } + + [CommandCmif(0)] + // Initialize() + public ResultCode Initialize(ServiceCtx context) + { + context.ResponseData.Write(0); + + return ResultCode.Success; + } + + [CommandCmif(256)] + // AttachNetworkInterfaceStateChangeEvent() -> handle + public ResultCode AttachNetworkInterfaceStateChangeEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out _stateChangeEventHandle) != Result.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangeEventHandle); + + return ResultCode.Success; + } + + [CommandCmif(288)] + // GetGroupInfo(buffer) + public ResultCode GetGroupInfo(ServiceCtx context) + { + Logger.Stub?.PrintStub(LogClass.ServiceLdn); + + return ResultCode.Success; + } + + [CommandCmif(296)] + // GetGroupInfo2(buffer, buffer) + public ResultCode GetGroupInfo2(ServiceCtx context) + { + Logger.Stub?.PrintStub(LogClass.ServiceLdn); + + return ResultCode.Success; + } + + [CommandCmif(312)] + // GetIpConfig(buffer, 0x1a>) + public ResultCode GetIpConfig(ServiceCtx context) + { + Logger.Stub?.PrintStub(LogClass.ServiceLdn); + + return ResultCode.Success; + } + + [CommandCmif(328)] + // AttachNetworkInterfaceStateChangeEvent() -> handle + public ResultCode AttachJoinEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_jointEvent.ReadableEvent, out _jointEventHandle) != Result.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_jointEventHandle); + + return ResultCode.Success; + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/LdnRyu/Proxy/P2pProxyServer.cs b/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/LdnRyu/Proxy/P2pProxyServer.cs index 598fb654f..fbce5c10c 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/LdnRyu/Proxy/P2pProxyServer.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/LdnRyu/Proxy/P2pProxyServer.cs @@ -1,3 +1,5 @@ +using Gommon; +using Humanizer; using NetCoreServer; using Open.Nat; using Ryujinx.Common.Logging; @@ -153,7 +155,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy if (_publicPort != 0) { - _ = Task.Delay(PortLeaseRenew * 1000, _disposedCancellation.Token).ContinueWith((task) => Task.Run(RefreshLease)); + _ = Executor.ExecuteAfterDelayAsync( + PortLeaseRenew.Seconds(), + _disposedCancellation.Token, + RefreshLease); } _natDevice = device; @@ -257,7 +262,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy } - _ = Task.Delay(PortLeaseRenew, _disposedCancellation.Token).ContinueWith((task) => Task.Run(RefreshLease)); + _ = Executor.ExecuteAfterDelayAsync( + PortLeaseRenew.Milliseconds(), + _disposedCancellation.Token, + RefreshLease); } public bool TryRegisterUser(P2pProxySession session, ExternalProxyConfig config) diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs index 7ce749d1a..0c685471c 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs @@ -93,6 +93,13 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp return registerInfo; } + public static void UpdateNickName(string amiiboId, string newNickName) + { + VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId); + virtualAmiiboFile.NickName = newNickName; + SaveAmiiboFile(virtualAmiiboFile); + } + public static bool OpenApplicationArea(string amiiboId, uint applicationAreaId) { VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId); diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs index 4c17e7aed..601e85867 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs @@ -10,13 +10,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; +using VSyncMode = Ryujinx.Common.Configuration.VSyncMode; namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { class SurfaceFlinger : IConsumerListener, IDisposable { - private const int TargetFps = 60; - private readonly Switch _device; private readonly Dictionary _layers; @@ -32,6 +31,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger private readonly long _spinTicks; private readonly long _1msTicks; + private VSyncMode _vSyncMode; + private long _targetVSyncInterval; + private int _swapInterval; private int _swapIntervalDelay; @@ -88,7 +90,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger } else { - _ticksPerFrame = Stopwatch.Frequency / TargetFps; + _ticksPerFrame = Stopwatch.Frequency / _device.TargetVSyncInterval; + _targetVSyncInterval = _device.TargetVSyncInterval; } } @@ -370,15 +373,20 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger if (acquireStatus == Status.Success) { - // If device vsync is disabled, reflect the change. - if (!_device.EnableDeviceVsync) + if (_device.VSyncMode == VSyncMode.Unbounded) { if (_swapInterval != 0) { UpdateSwapInterval(0); + _vSyncMode = _device.VSyncMode; } } - else if (item.SwapInterval != _swapInterval) + else if (_device.VSyncMode != _vSyncMode) + { + UpdateSwapInterval(_device.VSyncMode == VSyncMode.Unbounded ? 0 : item.SwapInterval); + _vSyncMode = _device.VSyncMode; + } + else if (item.SwapInterval != _swapInterval || _device.TargetVSyncInterval != _targetVSyncInterval) { UpdateSwapInterval(item.SwapInterval); } diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs index 2928ac7fe..361a9159e 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs @@ -26,7 +26,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions { private static readonly TitleUpdateMetadataJsonSerializerContext _applicationSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca) + public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca, BlitStruct? customNacpData = null) { // Extract RomFs and ExeFs from NCA. IStorage romFs = nca.GetRomFs(device, patchNca); @@ -55,6 +55,10 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions { nacpData = controlNca.GetNacp(device); } + else if (customNacpData != null) // if the Application doesn't provide a nacp file but the Application provides an override, use the provided nacp override + { + nacpData = (BlitStruct)customNacpData; + } /* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" non-existent update. diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs index a0e7e0fa1..fe8360f04 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs @@ -98,12 +98,12 @@ namespace Ryujinx.HLE.Loaders.Processes return false; } - public bool LoadNca(string path) + public bool LoadNca(string path, BlitStruct? customNacpData = null) { FileStream file = new(path, FileMode.Open, FileAccess.Read); Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false)); - ProcessResult processResult = nca.Load(_device, null, null); + ProcessResult processResult = nca.Load(_device, null, null, customNacpData); if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult)) { diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessResult.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessResult.cs index e187b2360..3a7042670 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessResult.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessResult.cs @@ -84,12 +84,19 @@ namespace Ryujinx.HLE.Loaders.Processes return false; } + bool isFirmware = ProgramId is >= 0x0100000000000819 and <= 0x010000000000081C; + bool isFirmwareApplication = ProgramId <= 0x0100000000007FFF; + + string name = !isFirmware + ? (isFirmwareApplication ? "Firmware Application " : "") + (!string.IsNullOrWhiteSpace(Name) ? Name : "") + : "Firmware"; + // TODO: LibHac npdm currently doesn't support version field. - string version = ProgramId > 0x0100000000007FFF - ? DisplayVersion + string version = !isFirmware + ? (!string.IsNullOrWhiteSpace(DisplayVersion) ? DisplayVersion : "") : device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?"; - Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {Name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]"); + Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]"); return true; } diff --git a/src/Ryujinx.HLE/Ryujinx.HLE.csproj b/src/Ryujinx.HLE/Ryujinx.HLE.csproj index 5f7f6db69..83e7b8810 100644 --- a/src/Ryujinx.HLE/Ryujinx.HLE.csproj +++ b/src/Ryujinx.HLE/Ryujinx.HLE.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.HLE/StructHelpers.cs b/src/Ryujinx.HLE/StructHelpers.cs new file mode 100644 index 000000000..6e6af8cea --- /dev/null +++ b/src/Ryujinx.HLE/StructHelpers.cs @@ -0,0 +1,37 @@ +using LibHac.Common; +using LibHac.Ns; +using System; +using System.Text; + +namespace Ryujinx.HLE +{ + public static class StructHelpers + { + public static BlitStruct CreateCustomNacpData(string name, string version) + { + // https://switchbrew.org/wiki/NACP + const int OffsetOfDisplayVersion = 0x3060; + + // https://switchbrew.org/wiki/NACP#ApplicationTitle + const int TotalApplicationTitles = 0x10; + const int SizeOfApplicationTitle = 0x300; + const int OffsetOfApplicationPublisherStrings = 0x200; + + + var nacpData = new BlitStruct(1); + + // name and publisher buffer + // repeat once for each locale (the ApplicationControlProperty has 16 locales) + for (int i = 0; i < TotalApplicationTitles; i++) + { + Encoding.ASCII.GetBytes(name).AsSpan().CopyTo(nacpData.ByteSpan[(i * SizeOfApplicationTitle)..]); + "Ryujinx"u8.CopyTo(nacpData.ByteSpan[(i * SizeOfApplicationTitle + OffsetOfApplicationPublisherStrings)..]); + } + + // version buffer + Encoding.ASCII.GetBytes(version).AsSpan().CopyTo(nacpData.ByteSpan[OffsetOfDisplayVersion..]); + + return nacpData; + } + } +} diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index d12cb8f77..d0afdf173 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -1,3 +1,5 @@ +using LibHac.Common; +using LibHac.Ns; using Ryujinx.Audio.Backends.CompatLayer; using Ryujinx.Audio.Integration; using Ryujinx.Common.Configuration; @@ -27,7 +29,11 @@ namespace Ryujinx.HLE public TamperMachine TamperMachine { get; } public IHostUIHandler UIHandler { get; } - public bool EnableDeviceVsync { get; set; } + public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch; + public bool CustomVSyncIntervalEnabled { get; set; } = false; + public int CustomVSyncInterval { get; set; } + + public long TargetVSyncInterval { get; set; } = 60; public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable; @@ -59,12 +65,14 @@ namespace Ryujinx.HLE System.State.SetLanguage(Configuration.SystemLanguage); System.State.SetRegion(Configuration.Region); - EnableDeviceVsync = Configuration.EnableVsync; + VSyncMode = Configuration.VSyncMode; + CustomVSyncInterval = Configuration.CustomVSyncInterval; System.State.DockedMode = Configuration.EnableDockedMode; System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default; System.EnablePtc = Configuration.EnablePtc; System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel; System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode; + UpdateVSyncInterval(); #pragma warning restore IDE0055 } @@ -75,9 +83,37 @@ namespace Ryujinx.HLE Gpu.GPFifo.DispatchCalls(); } + public void IncrementCustomVSyncInterval() + { + CustomVSyncInterval += 1; + UpdateVSyncInterval(); + } + + public void DecrementCustomVSyncInterval() + { + CustomVSyncInterval -= 1; + UpdateVSyncInterval(); + } + + public void UpdateVSyncInterval() + { + switch (VSyncMode) + { + case VSyncMode.Custom: + TargetVSyncInterval = CustomVSyncInterval; + break; + case VSyncMode.Switch: + TargetVSyncInterval = 60; + break; + case VSyncMode.Unbounded: + TargetVSyncInterval = 1; + break; + } + } + public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile); public bool LoadXci(string xciFile, ulong applicationId = 0) => Processes.LoadXci(xciFile, applicationId); - public bool LoadNca(string ncaFile) => Processes.LoadNca(ncaFile); + public bool LoadNca(string ncaFile, BlitStruct? customNacpData = null) => Processes.LoadNca(ncaFile, customNacpData); public bool LoadNsp(string nspFile, ulong applicationId = 0) => Processes.LoadNsp(nspFile, applicationId); public bool LoadProgram(string fileName) => Processes.LoadNxo(fileName); diff --git a/src/Ryujinx.HLE/UI/IHostUIHandler.cs b/src/Ryujinx.HLE/UI/IHostUIHandler.cs index 8debfcca0..88af83735 100644 --- a/src/Ryujinx.HLE/UI/IHostUIHandler.cs +++ b/src/Ryujinx.HLE/UI/IHostUIHandler.cs @@ -24,6 +24,18 @@ namespace Ryujinx.HLE.UI /// True when OK is pressed, False otherwise. bool DisplayMessageDialog(ControllerAppletUIArgs args); + /// + /// Displays an Input Dialog box to the user so they can enter the Amiibo's new name + /// + /// Text that the user entered. Set to `null` on internal errors + /// True when OK is pressed, False otherwise. Also returns True on internal errors + bool DisplayCabinetDialog(out string userText); + + /// + /// Displays a Message Dialog box to the user to notify them to scan the Amiibo. + /// + void DisplayCabinetMessageDialog(); + /// /// Tell the UI that we need to transition to another program. /// diff --git a/src/Ryujinx.Headless.SDL2/Options.cs b/src/Ryujinx.Headless.SDL2/Options.cs index 8078ca5e4..4e2ad5b58 100644 --- a/src/Ryujinx.Headless.SDL2/Options.cs +++ b/src/Ryujinx.Headless.SDL2/Options.cs @@ -115,8 +115,11 @@ namespace Ryujinx.Headless.SDL2 [Option("fs-global-access-log-mode", Required = false, Default = 0, HelpText = "Enables FS access log output to the console.")] public int FsGlobalAccessLogMode { get; set; } - [Option("disable-vsync", Required = false, HelpText = "Disables Vertical Sync.")] - public bool DisableVSync { get; set; } + [Option("vsync-mode", Required = false, Default = VSyncMode.Switch, HelpText = "Sets the emulated VSync mode (Switch, Unbounded, or Custom).")] + public VSyncMode VSyncMode { get; set; } + + [Option("custom-refresh-rate", Required = false, Default = 90, HelpText = "Sets the custom refresh rate target value (integer).")] + public int CustomVSyncInterval { get; set; } [Option("disable-shader-cache", Required = false, HelpText = "Disables Shader cache.")] public bool DisableShaderCache { get; set; } diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index e3bbd1e51..12158176a 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -1,4 +1,5 @@ using CommandLine; +using Gommon; using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Common; @@ -96,8 +97,13 @@ namespace Ryujinx.Headless.SDL2 } Parser.Default.ParseArguments(args) - .WithParsed(Load) - .WithNotParsed(errors => errors.Output()); + .WithParsed(Load) + .WithNotParsed(errors => + { + Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:"); + + errors.ForEach(err => Logger.Error?.PrintMsg(LogClass.Application, $" - {err.Tag}")); + }); } private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index) @@ -563,7 +569,7 @@ namespace Ryujinx.Headless.SDL2 window, options.SystemLanguage, options.SystemRegion, - !options.DisableVSync, + options.VSyncMode, !options.DisableDockedMode, !options.DisablePTC, options.EnableInternetAccess, @@ -579,8 +585,9 @@ namespace Ryujinx.Headless.SDL2 options.MultiplayerLanInterfaceId, Common.Configuration.Multiplayer.MultiplayerMode.Disabled, false, - "", - ""); + string.Empty, + string.Empty, + options.CustomVSyncInterval); return new Switch(configuration); } diff --git a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj index ebda97b46..8fbf9be1e 100644 --- a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj +++ b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj @@ -9,6 +9,7 @@ $(DefineConstants);$(ExtraDefineConstants) - true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Headless.SDL2/StatusUpdatedEventArgs.cs b/src/Ryujinx.Headless.SDL2/StatusUpdatedEventArgs.cs index cd7715712..c1dd3805f 100644 --- a/src/Ryujinx.Headless.SDL2/StatusUpdatedEventArgs.cs +++ b/src/Ryujinx.Headless.SDL2/StatusUpdatedEventArgs.cs @@ -3,7 +3,7 @@ using System; namespace Ryujinx.Headless.SDL2 { class StatusUpdatedEventArgs( - bool vSyncEnabled, + string vSyncMode, string dockedMode, string aspectRatio, string gameStatus, @@ -11,7 +11,7 @@ namespace Ryujinx.Headless.SDL2 string gpuName) : EventArgs { - public bool VSyncEnabled = vSyncEnabled; + public string VSyncMode = vSyncMode; public string DockedMode = dockedMode; public string AspectRatio = aspectRatio; public string GameStatus = gameStatus; diff --git a/src/Ryujinx.Headless.SDL2/WindowBase.cs b/src/Ryujinx.Headless.SDL2/WindowBase.cs index 6d681e100..fbe7cb49c 100644 --- a/src/Ryujinx.Headless.SDL2/WindowBase.cs +++ b/src/Ryujinx.Headless.SDL2/WindowBase.cs @@ -1,4 +1,5 @@ using Humanizer; +using LibHac.Tools.Fs; using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Logging; @@ -314,7 +315,7 @@ namespace Ryujinx.Headless.SDL2 } StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs( - Device.EnableDeviceVsync, + Device.VSyncMode.ToString(), dockedMode, Device.Configuration.AspectRatio.ToText(), $"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", @@ -485,6 +486,19 @@ namespace Ryujinx.Headless.SDL2 return true; } + public bool DisplayCabinetDialog(out string userText) + { + // SDL2 doesn't support input dialogs + userText = "Ryujinx"; + + return true; + } + + public void DisplayCabinetMessageDialog() + { + SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags.SDL_MESSAGEBOX_INFORMATION, "Cabinet Dialog", "Please scan your Amiibo now.", WindowHandle); + } + public bool DisplayMessageDialog(ControllerAppletUIArgs args) { if (_ignoreControllerApplet) return false; diff --git a/src/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj b/src/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj index fa1544c4f..00e0b1af9 100644 --- a/src/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj +++ b/src/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj b/src/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj index d58803993..416eefc27 100644 --- a/src/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj +++ b/src/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj @@ -3,6 +3,7 @@ netstandard2.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj b/src/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj index d58803993..02a8ec2c6 100644 --- a/src/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj +++ b/src/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj @@ -3,6 +3,8 @@ netstandard2.0 true + $(DefaultItemExcludes);._* + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Horizon/Ryujinx.Horizon.csproj b/src/Ryujinx.Horizon/Ryujinx.Horizon.csproj index bf34ddd17..18c639d67 100644 --- a/src/Ryujinx.Horizon/Ryujinx.Horizon.csproj +++ b/src/Ryujinx.Horizon/Ryujinx.Horizon.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj b/src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj index 1ab79d08a..3d880d5fa 100644 --- a/src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj +++ b/src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Input/Ryujinx.Input.csproj b/src/Ryujinx.Input/Ryujinx.Input.csproj index 59a9eeb61..0974b707a 100644 --- a/src/Ryujinx.Input/Ryujinx.Input.csproj +++ b/src/Ryujinx.Input/Ryujinx.Input.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Memory/Ryujinx.Memory.csproj b/src/Ryujinx.Memory/Ryujinx.Memory.csproj index 8310a3e5c..17745dd61 100644 --- a/src/Ryujinx.Memory/Ryujinx.Memory.csproj +++ b/src/Ryujinx.Memory/Ryujinx.Memory.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Memory/SparseMemoryBlock.cs b/src/Ryujinx.Memory/SparseMemoryBlock.cs new file mode 100644 index 000000000..523685de1 --- /dev/null +++ b/src/Ryujinx.Memory/SparseMemoryBlock.cs @@ -0,0 +1,125 @@ +using Ryujinx.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace Ryujinx.Memory +{ + public delegate void PageInitDelegate(Span page); + + public class SparseMemoryBlock : IDisposable + { + private const ulong MapGranularity = 1UL << 17; + + private readonly PageInitDelegate _pageInit; + + private readonly object _lock = new object(); + private readonly ulong _pageSize; + private readonly MemoryBlock _reservedBlock; + private readonly List _mappedBlocks; + private ulong _mappedBlockUsage; + + private readonly ulong[] _mappedPageBitmap; + + public MemoryBlock Block => _reservedBlock; + + public SparseMemoryBlock(ulong size, PageInitDelegate pageInit, MemoryBlock fill) + { + _pageSize = MemoryBlock.GetPageSize(); + _reservedBlock = new MemoryBlock(size, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible); + _mappedBlocks = new List(); + _pageInit = pageInit; + + int pages = (int)BitUtils.DivRoundUp(size, _pageSize); + int bitmapEntries = BitUtils.DivRoundUp(pages, 64); + _mappedPageBitmap = new ulong[bitmapEntries]; + + if (fill != null) + { + // Fill the block with mappings from the fill block. + + if (fill.Size % _pageSize != 0) + { + throw new ArgumentException("Fill memory block should be page aligned.", nameof(fill)); + } + + int repeats = (int)BitUtils.DivRoundUp(size, fill.Size); + + ulong offset = 0; + for (int i = 0; i < repeats; i++) + { + _reservedBlock.MapView(fill, 0, offset, Math.Min(fill.Size, size - offset)); + offset += fill.Size; + } + } + + // If a fill block isn't provided, the pages that aren't EnsureMapped are unmapped. + // The caller can rely on signal handler to fill empty pages instead. + } + + private void MapPage(ulong pageOffset) + { + // Take a page from the latest mapped block. + MemoryBlock block = _mappedBlocks.LastOrDefault(); + + if (block == null || _mappedBlockUsage == MapGranularity) + { + // Need to map some more memory. + + block = new MemoryBlock(MapGranularity, MemoryAllocationFlags.Mirrorable); + + _mappedBlocks.Add(block); + + _mappedBlockUsage = 0; + } + + _pageInit(block.GetSpan(_mappedBlockUsage, (int)_pageSize)); + _reservedBlock.MapView(block, _mappedBlockUsage, pageOffset, _pageSize); + + _mappedBlockUsage += _pageSize; + } + + public void EnsureMapped(ulong offset) + { + int pageIndex = (int)(offset / _pageSize); + int bitmapIndex = pageIndex >> 6; + + ref ulong entry = ref _mappedPageBitmap[bitmapIndex]; + ulong bit = 1UL << (pageIndex & 63); + + if ((Volatile.Read(ref entry) & bit) == 0) + { + // Not mapped. + + lock (_lock) + { + // Check the bit while locked to make sure that this only happens once. + + ulong lockedEntry = Volatile.Read(ref entry); + + if ((lockedEntry & bit) == 0) + { + MapPage(offset & ~(_pageSize - 1)); + + lockedEntry |= bit; + + Interlocked.Exchange(ref entry, lockedEntry); + } + } + } + } + + public void Dispose() + { + _reservedBlock.Dispose(); + + foreach (MemoryBlock block in _mappedBlocks) + { + block.Dispose(); + } + + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.SDL2.Common/Ryujinx.SDL2.Common.csproj b/src/Ryujinx.SDL2.Common/Ryujinx.SDL2.Common.csproj index 8e7953045..0811ad850 100644 --- a/src/Ryujinx.SDL2.Common/Ryujinx.SDL2.Common.csproj +++ b/src/Ryujinx.SDL2.Common/Ryujinx.SDL2.Common.csproj @@ -2,6 +2,7 @@ net8.0 + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj b/src/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj index ab89fb5c7..639ceeac2 100644 --- a/src/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj +++ b/src/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj @@ -4,6 +4,7 @@ net8.0 Exe Debug;Release + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj b/src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj index f05060838..3bb4bf74d 100644 --- a/src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj +++ b/src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj @@ -3,6 +3,7 @@ net8.0 false + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj b/src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj index befacfb22..2f7695356 100644 --- a/src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj +++ b/src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj @@ -4,6 +4,7 @@ net8.0 true Debug;Release + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.Tests/Cpu/CpuContext.cs b/src/Ryujinx.Tests/Cpu/CpuContext.cs index 96b4965a2..81e8ba8c9 100644 --- a/src/Ryujinx.Tests/Cpu/CpuContext.cs +++ b/src/Ryujinx.Tests/Cpu/CpuContext.cs @@ -1,3 +1,4 @@ +using ARMeilleure.Common; using ARMeilleure.Memory; using ARMeilleure.State; using ARMeilleure.Translation; @@ -12,7 +13,7 @@ namespace Ryujinx.Tests.Cpu public CpuContext(IMemoryManager memory, bool for64Bit) { - _translator = new Translator(new JitMemoryAllocator(), memory, for64Bit); + _translator = new Translator(new JitMemoryAllocator(), memory, AddressTable.CreateForArm(for64Bit, memory.Type)); memory.UnmapEvent += UnmapHandler; } diff --git a/src/Ryujinx.Tests/Cpu/EnvironmentTests.cs b/src/Ryujinx.Tests/Cpu/EnvironmentTests.cs index 2a4775a31..43c84c193 100644 --- a/src/Ryujinx.Tests/Cpu/EnvironmentTests.cs +++ b/src/Ryujinx.Tests/Cpu/EnvironmentTests.cs @@ -1,3 +1,5 @@ +using ARMeilleure.Common; +using ARMeilleure.Memory; using ARMeilleure.Translation; using NUnit.Framework; using Ryujinx.Cpu.Jit; @@ -17,7 +19,10 @@ namespace Ryujinx.Tests.Cpu private static void EnsureTranslator() { // Create a translator, as one is needed to register the signal handler or emit methods. - _translator ??= new Translator(new JitMemoryAllocator(), new MockMemoryManager(), true); + _translator ??= new Translator( + new JitMemoryAllocator(), + new MockMemoryManager(), + AddressTable.CreateForArm(true, MemoryManagerType.SoftwarePageTable)); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] diff --git a/src/Ryujinx.Tests/Memory/PartialUnmaps.cs b/src/Ryujinx.Tests/Memory/PartialUnmaps.cs index 6d2ad8fb0..3e5b47423 100644 --- a/src/Ryujinx.Tests/Memory/PartialUnmaps.cs +++ b/src/Ryujinx.Tests/Memory/PartialUnmaps.cs @@ -1,3 +1,5 @@ +using ARMeilleure.Common; +using ARMeilleure.Memory; using ARMeilleure.Signal; using ARMeilleure.Translation; using NUnit.Framework; @@ -53,7 +55,10 @@ namespace Ryujinx.Tests.Memory private static void EnsureTranslator() { // Create a translator, as one is needed to register the signal handler or emit methods. - _translator ??= new Translator(new JitMemoryAllocator(), new MockMemoryManager(), true); + _translator ??= new Translator( + new JitMemoryAllocator(), + new MockMemoryManager(), + AddressTable.CreateForArm(true, MemoryManagerType.SoftwarePageTable)); } [Test] diff --git a/src/Ryujinx.Tests/Ryujinx.Tests.csproj b/src/Ryujinx.Tests/Ryujinx.Tests.csproj index 3be9787a3..0480c206e 100644 --- a/src/Ryujinx.Tests/Ryujinx.Tests.csproj +++ b/src/Ryujinx.Tests/Ryujinx.Tests.csproj @@ -10,6 +10,7 @@ linux Debug;Release $(MSBuildProjectDirectory)\.runsettings + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs index 174db51ad..cb6467f5e 100644 --- a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs @@ -1,5 +1,4 @@ using DynamicData; -using DynamicData.Kernel; using Gommon; using LibHac; using LibHac.Common; @@ -37,14 +36,13 @@ using System.Threading.Tasks; using ContentType = LibHac.Ncm.ContentType; using MissingKeyException = LibHac.Common.Keys.MissingKeyException; using Path = System.IO.Path; -using SpanHelpers = LibHac.Common.SpanHelpers; using TimeSpan = System.TimeSpan; namespace Ryujinx.UI.App.Common { public class ApplicationLibrary { - public static string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com"; + public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com"; public Language DesiredLanguage { get; set; } public event EventHandler ApplicationCountUpdated; public event EventHandler LdnGameDataReceived; @@ -191,12 +189,9 @@ namespace Ryujinx.UI.App.Common } } - if (isExeFs) - { - return GetApplicationFromExeFs(pfs, filePath); - } - - return null; + return isExeFs + ? GetApplicationFromExeFs(pfs, filePath) + : null; } /// The configured key set is missing a key. @@ -512,10 +507,6 @@ namespace Ryujinx.UI.App.Common case ".xci": case ".nsp": { - IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks - ? IntegrityCheckLevel.ErrorOnInvalid - : IntegrityCheckLevel.None; - using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem); foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) @@ -604,7 +595,7 @@ namespace Ryujinx.UI.App.Common controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None) .OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read) .ThrowIfFailure(); - nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), + nacpFile.Get.Read(out _, 0, LibHac.Common.SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); var displayVersion = controlData.DisplayVersionString.ToString(); @@ -827,7 +818,7 @@ namespace Ryujinx.UI.App.Common { _downloadableContents.Edit(it => { - DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, application.IdBase, dlcs); + DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase, dlcs); it.Remove(it.Items.Where(item => item.Dlc.TitleIdBase == application.IdBase)); it.AddOrUpdate(dlcs); @@ -839,7 +830,7 @@ namespace Ryujinx.UI.App.Common { _titleUpdates.Edit(it => { - TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, application.IdBase, updates); + TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, updates); it.Remove(it.Items.Where(item => item.TitleUpdate.TitleIdBase == application.IdBase)); it.AddOrUpdate(updates); @@ -1088,14 +1079,15 @@ namespace Ryujinx.UI.App.Common private bool AddAndAutoSelectUpdate(TitleUpdateModel update) { - var currentlySelected = TitleUpdates.Items.FirstOrOptional(it => + if (update == null) return false; + + var currentlySelected = TitleUpdates.Items.FindFirst(it => it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected); - var shouldSelect = !currentlySelected.HasValue || - currentlySelected.Value.TitleUpdate.Version < update.Version; + var shouldSelect = currentlySelected.Check(curr => curr.TitleUpdate?.Version < update.Version); _titleUpdates.AddOrUpdate((update, shouldSelect)); - + if (currentlySelected.HasValue && shouldSelect) { _titleUpdates.AddOrUpdate((currentlySelected.Value.TitleUpdate, false)); @@ -1464,7 +1456,7 @@ namespace Ryujinx.UI.App.Common if (addedNewDlc) { var gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList(); - DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, application.IdBase, + DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase, gameDlcs); } } @@ -1483,11 +1475,11 @@ namespace Ryujinx.UI.App.Common TitleUpdatesHelper.LoadTitleUpdatesJson(_virtualFileSystem, application.IdBase); it.AddOrUpdate(savedUpdates); - var selectedUpdate = savedUpdates.FirstOrOptional(update => update.IsSelected); + var selectedUpdate = savedUpdates.FindFirst(update => update.IsSelected); if (TryGetTitleUpdatesFromFile(application.Path, out var bundledUpdates)) { - var savedUpdateLookup = savedUpdates.Select(update => update.Item1).ToHashSet(); + var savedUpdateLookup = savedUpdates.Select(update => update.Update).ToHashSet(); bool updatesChanged = false; foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version)) @@ -1495,12 +1487,11 @@ namespace Ryujinx.UI.App.Common if (!savedUpdateLookup.Contains(update)) { bool shouldSelect = false; - if (!selectedUpdate.HasValue || selectedUpdate.Value.Item1.Version < update.Version) + if (selectedUpdate.Check(su => su.Update?.Version < update.Version)) { shouldSelect = true; - if (selectedUpdate.HasValue) - _titleUpdates.AddOrUpdate((selectedUpdate.Value.Item1, false)); - selectedUpdate = DynamicData.Kernel.Optional<(TitleUpdateModel, bool IsSelected)>.Create((update, true)); + _titleUpdates.AddOrUpdate((selectedUpdate.Value.Update, false)); + selectedUpdate = (update, true); } modifiedVersion = modifiedVersion || shouldSelect; @@ -1513,7 +1504,7 @@ namespace Ryujinx.UI.App.Common if (updatesChanged) { var gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList(); - TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, application.IdBase, gameUpdates); + TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, gameUpdates); } } }); @@ -1525,14 +1516,14 @@ namespace Ryujinx.UI.App.Common private void SaveDownloadableContentsForGame(ulong titleIdBase) { var dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList(); - DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, titleIdBase, dlcs); + DownloadableContentsHelper.SaveDownloadableContentsJson(titleIdBase, dlcs); } // Save the _currently tracked_ update state for the game private void SaveTitleUpdatesForGame(ulong titleIdBase) { var updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList(); - TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, titleIdBase, updates); + TitleUpdatesHelper.SaveTitleUpdatesJson(titleIdBase, updates); } // ApplicationData isnt live-updating (e.g. when an update gets applied) and so this is meant to trigger a refresh diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs index 80ba1b186..027e1052b 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Multiplayer; @@ -16,7 +17,7 @@ namespace Ryujinx.UI.Common.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 56; + public const int CurrentVersion = 57; /// /// Version of the configuration file format @@ -191,8 +192,25 @@ namespace Ryujinx.UI.Common.Configuration /// /// Enables or disables Vertical Sync /// + /// Kept for file format compatibility (to avoid possible failure when parsing configuration on old versions) + /// TODO: Remove this when those older versions aren't in use anymore. public bool EnableVsync { get; set; } + /// + /// Current VSync mode; 60 (Switch), unbounded ("Vsync off"), or custom + /// + public VSyncMode VSyncMode { get; set; } + + /// + /// Enables or disables the custom present interval + /// + public bool EnableCustomVSyncInterval { get; set; } + + /// + /// The custom present interval value + /// + public int CustomVSyncInterval { get; set; } + /// /// Enables or disables Shader cache /// diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs index 65dd88106..a41ea2cd7 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs @@ -82,7 +82,7 @@ namespace Ryujinx.UI.Common.Configuration configurationFileFormat.Hotkeys = new KeyboardHotkeys { - ToggleVsync = Key.F1, + ToggleVSyncMode = Key.F1, }; configurationFileUpdated = true; @@ -276,7 +276,7 @@ namespace Ryujinx.UI.Common.Configuration configurationFileFormat.Hotkeys = new KeyboardHotkeys { - ToggleVsync = Key.F1, + ToggleVSyncMode = Key.F1, Screenshot = Key.F8, }; @@ -289,7 +289,7 @@ namespace Ryujinx.UI.Common.Configuration configurationFileFormat.Hotkeys = new KeyboardHotkeys { - ToggleVsync = Key.F1, + ToggleVSyncMode = Key.F1, Screenshot = Key.F8, ShowUI = Key.F4, }; @@ -332,7 +332,7 @@ namespace Ryujinx.UI.Common.Configuration configurationFileFormat.Hotkeys = new KeyboardHotkeys { - ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, + ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode, Screenshot = configurationFileFormat.Hotkeys.Screenshot, ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = Key.F5, @@ -347,7 +347,7 @@ namespace Ryujinx.UI.Common.Configuration configurationFileFormat.Hotkeys = new KeyboardHotkeys { - ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, + ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode, Screenshot = configurationFileFormat.Hotkeys.Screenshot, ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, @@ -421,7 +421,7 @@ namespace Ryujinx.UI.Common.Configuration configurationFileFormat.Hotkeys = new KeyboardHotkeys { - ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, + ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode, Screenshot = configurationFileFormat.Hotkeys.Screenshot, ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, @@ -448,7 +448,7 @@ namespace Ryujinx.UI.Common.Configuration configurationFileFormat.Hotkeys = new KeyboardHotkeys { - ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, + ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode, Screenshot = configurationFileFormat.Hotkeys.Screenshot, ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, @@ -611,6 +611,33 @@ namespace Ryujinx.UI.Common.Configuration configurationFileUpdated = true; } + if (configurationFileFormat.Version < 57) + { + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 57."); + + configurationFileFormat.VSyncMode = VSyncMode.Switch; + configurationFileFormat.EnableCustomVSyncInterval = false; + + configurationFileFormat.Hotkeys = new KeyboardHotkeys + { + ToggleVSyncMode = Key.F1, + Screenshot = configurationFileFormat.Hotkeys.Screenshot, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, + Pause = configurationFileFormat.Hotkeys.Pause, + ToggleMute = configurationFileFormat.Hotkeys.ToggleMute, + ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp, + ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown, + VolumeUp = configurationFileFormat.Hotkeys.VolumeUp, + VolumeDown = configurationFileFormat.Hotkeys.VolumeDown, + CustomVSyncIntervalIncrement = Key.Unbound, + CustomVSyncIntervalDecrement = Key.Unbound, + }; + + configurationFileFormat.CustomVSyncInterval = 120; + + configurationFileUpdated = true; + } + Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; @@ -646,7 +673,9 @@ namespace Ryujinx.UI.Common.Configuration ShowTitleBar.Value = configurationFileFormat.ShowTitleBar; EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration; HideCursor.Value = configurationFileFormat.HideCursor; - Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync; + Graphics.VSyncMode.Value = configurationFileFormat.VSyncMode; + Graphics.EnableCustomVSyncInterval.Value = configurationFileFormat.EnableCustomVSyncInterval; + Graphics.CustomVSyncInterval.Value = configurationFileFormat.CustomVSyncInterval; Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache; Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression; Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE; diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs index 9be8f4df7..f28ce0348 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs @@ -1,4 +1,4 @@ -using ARMeilleure; +using ARMeilleure; using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; @@ -474,9 +474,19 @@ namespace Ryujinx.UI.Common.Configuration public ReactiveObject ShadersDumpPath { get; private set; } /// - /// Enables or disables Vertical Sync + /// Toggles the present interval mode. Options are Switch (60Hz), Unbounded (previously Vsync off), and Custom, if enabled. /// - public ReactiveObject EnableVsync { get; private set; } + public ReactiveObject VSyncMode { get; private set; } + + /// + /// Enables or disables the custom present interval mode. + /// + public ReactiveObject EnableCustomVSyncInterval { get; private set; } + + /// + /// Changes the custom present interval. + /// + public ReactiveObject CustomVSyncInterval { get; private set; } /// /// Enables or disables Shader cache @@ -536,8 +546,12 @@ namespace Ryujinx.UI.Common.Configuration AspectRatio = new ReactiveObject(); AspectRatio.LogChangesToValue(nameof(AspectRatio)); ShadersDumpPath = new ReactiveObject(); - EnableVsync = new ReactiveObject(); - EnableVsync.LogChangesToValue(nameof(EnableVsync)); + VSyncMode = new ReactiveObject(); + VSyncMode.LogChangesToValue(nameof(VSyncMode)); + EnableCustomVSyncInterval = new ReactiveObject(); + EnableCustomVSyncInterval.LogChangesToValue(nameof(EnableCustomVSyncInterval)); + CustomVSyncInterval = new ReactiveObject(); + CustomVSyncInterval.LogChangesToValue(nameof(CustomVSyncInterval)); EnableShaderCache = new ReactiveObject(); EnableShaderCache.LogChangesToValue(nameof(EnableShaderCache)); EnableTextureRecompression = new ReactiveObject(); diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs index b3012568e..04ddd442f 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs @@ -1,16 +1,12 @@ -using ARMeilleure; using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Configuration.Multiplayer; -using Ryujinx.Common.Logging; using Ryujinx.Graphics.Vulkan; using Ryujinx.HLE; using Ryujinx.UI.Common.Configuration.System; using Ryujinx.UI.Common.Configuration.UI; using System; -using System.Collections.Generic; namespace Ryujinx.UI.Common.Configuration { @@ -21,10 +17,10 @@ namespace Ryujinx.UI.Common.Configuration if (Instance != null) { throw new InvalidOperationException("Configuration is already initialized"); - } + } Instance = new ConfigurationState(); - } + } public ConfigurationFileFormat ToFileFormat() { @@ -64,7 +60,9 @@ namespace Ryujinx.UI.Common.Configuration ShowTitleBar = ShowTitleBar, EnableHardwareAcceleration = EnableHardwareAcceleration, HideCursor = HideCursor, - EnableVsync = Graphics.EnableVsync, + VSyncMode = Graphics.VSyncMode, + EnableCustomVSyncInterval = Graphics.EnableCustomVSyncInterval, + CustomVSyncInterval = Graphics.CustomVSyncInterval, EnableShaderCache = Graphics.EnableShaderCache, EnableTextureRecompression = Graphics.EnableTextureRecompression, EnableMacroHLE = Graphics.EnableMacroHLE, @@ -179,7 +177,9 @@ namespace Ryujinx.UI.Common.Configuration ShowTitleBar.Value = !OperatingSystem.IsWindows(); EnableHardwareAcceleration.Value = true; HideCursor.Value = HideCursorMode.OnIdle; - Graphics.EnableVsync.Value = true; + Graphics.VSyncMode.Value = VSyncMode.Switch; + Graphics.CustomVSyncInterval.Value = 120; + Graphics.EnableCustomVSyncInterval.Value = false; Graphics.EnableShaderCache.Value = true; Graphics.EnableTextureRecompression.Value = false; Graphics.EnableMacroHLE.Value = true; @@ -240,7 +240,7 @@ namespace Ryujinx.UI.Common.Configuration Hid.EnableMouse.Value = false; Hid.Hotkeys.Value = new KeyboardHotkeys { - ToggleVsync = Key.F1, + ToggleVSyncMode = Key.F1, ToggleMute = Key.F2, Screenshot = Key.F8, ShowUI = Key.F4, diff --git a/src/Ryujinx.UI.Common/DiscordIntegrationModule.cs b/src/Ryujinx.UI.Common/DiscordIntegrationModule.cs index a26f6a7b2..338d28531 100644 --- a/src/Ryujinx.UI.Common/DiscordIntegrationModule.cs +++ b/src/Ryujinx.UI.Common/DiscordIntegrationModule.cs @@ -247,6 +247,7 @@ namespace Ryujinx.UI.Common "0100dbf01000a000", // Burnout Paradise Remastered "0100744001588000", // Cars 3: Driven to Win "0100b41013c82000", // Cruis'n Blast + "01001b300b9be000", // Diablo III: Eternal Collection "01008c8012920000", // Dying Light Platinum Edition "010073c01af34000", // LEGO Horizon Adventures "0100770008dd8000", // Monster Hunter Generations Ultimate @@ -264,6 +265,7 @@ namespace Ryujinx.UI.Common "0100800015926000", // Suika Game "0100e46006708000", // Terraria "01000a10041ea000", // The Elder Scrolls V: Skyrim + "010057a01e4d4000", // TSUKIHIME -A piece of blue glass moon- "010080b00ad66000", // Undertale ]; } diff --git a/src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs b/src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs index 623952b37..99b209c6e 100644 --- a/src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs @@ -7,6 +7,24 @@ namespace Ryujinx.UI.Common.Helper { public static partial class ConsoleHelper { + [SupportedOSPlatform("windows")] + [LibraryImport("kernel32")] + private static partial nint GetConsoleWindow(); + + [SupportedOSPlatform("windows")] + [LibraryImport("user32")] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool ShowWindow(nint hWnd, int nCmdShow); + + [SupportedOSPlatform("windows")] + [LibraryImport("user32")] + private static partial nint GetForegroundWindow(); + + [SupportedOSPlatform("windows")] + [LibraryImport("user32")] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool SetForegroundWindow(nint hWnd); + public static bool SetConsoleWindowStateSupported => OperatingSystem.IsWindows(); public static void SetConsoleWindowState(bool show) @@ -35,16 +53,11 @@ namespace Ryujinx.UI.Common.Helper return; } + SetForegroundWindow(hWnd); + + hWnd = GetForegroundWindow(); + ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE); } - - [SupportedOSPlatform("windows")] - [LibraryImport("kernel32")] - private static partial nint GetConsoleWindow(); - - [SupportedOSPlatform("windows")] - [LibraryImport("user32")] - [return: MarshalAs(UnmanagedType.Bool)] - private static partial bool ShowWindow(nint hWnd, int nCmdShow); } } diff --git a/src/Ryujinx.UI.Common/Helper/DownloadableContentsHelper.cs b/src/Ryujinx.UI.Common/Helper/DownloadableContentsHelper.cs index 3695c5c5c..020529b55 100644 --- a/src/Ryujinx.UI.Common/Helper/DownloadableContentsHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/DownloadableContentsHelper.cs @@ -42,7 +42,7 @@ namespace Ryujinx.UI.Common.Helper } } - public static void SaveDownloadableContentsJson(VirtualFileSystem vfs, ulong applicationIdBase, List<(DownloadableContentModel, bool IsEnabled)> dlcs) + public static void SaveDownloadableContentsJson(ulong applicationIdBase, List<(DownloadableContentModel, bool IsEnabled)> dlcs) { DownloadableContentContainer container = default; List downloadableContentContainerList = new(); diff --git a/src/Ryujinx.UI.Common/Helper/TitleUpdatesHelper.cs b/src/Ryujinx.UI.Common/Helper/TitleUpdatesHelper.cs index 18fbabd6d..36de8b31a 100644 --- a/src/Ryujinx.UI.Common/Helper/TitleUpdatesHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/TitleUpdatesHelper.cs @@ -28,7 +28,7 @@ namespace Ryujinx.UI.Common.Helper { private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - public static List<(TitleUpdateModel, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase) + public static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase) { var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase); @@ -49,7 +49,7 @@ namespace Ryujinx.UI.Common.Helper } } - public static void SaveTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates) + public static void SaveTitleUpdatesJson(ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates) { var titleUpdateWindowData = new TitleUpdateMetadata { @@ -77,7 +77,7 @@ namespace Ryujinx.UI.Common.Helper JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata); } - private static List<(TitleUpdateModel, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase) + private static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase) { var result = new List<(TitleUpdateModel, bool IsSelected)>(); diff --git a/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png b/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png index 28067e908..e61358a95 100644 Binary files a/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png and b/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png differ diff --git a/src/Ryujinx.UI.Common/Resources/Logo_Thiccjinx.png b/src/Ryujinx.UI.Common/Resources/Logo_Thiccjinx.png new file mode 100644 index 000000000..be807a40a Binary files /dev/null and b/src/Ryujinx.UI.Common/Resources/Logo_Thiccjinx.png differ diff --git a/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj b/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj index df6532a63..00b0bacac 100644 --- a/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj +++ b/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj @@ -3,6 +3,7 @@ net8.0 true + $(DefaultItemExcludes);._* @@ -33,6 +34,7 @@ + diff --git a/src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj b/src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj index 05cbc7644..e4e627072 100644 --- a/src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj +++ b/src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj @@ -5,6 +5,7 @@ enable latest true + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx/App.axaml b/src/Ryujinx/App.axaml index 5a603509c..5c96f97f2 100644 --- a/src/Ryujinx/App.axaml +++ b/src/Ryujinx/App.axaml @@ -11,7 +11,7 @@ - + diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index 7246be4b9..65c798ac2 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -3,6 +3,8 @@ using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; using Avalonia.Threading; +using LibHac.Common; +using LibHac.Ns; using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.Dummy; using Ryujinx.Audio.Backends.OpenAL; @@ -57,6 +59,8 @@ using Key = Ryujinx.Input.Key; using MouseButton = Ryujinx.Input.MouseButton; using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter; using Size = Avalonia.Size; +using Switch = Ryujinx.HLE.Switch; +using VSyncMode = Ryujinx.Common.Configuration.VSyncMode; namespace Ryujinx.Ava { @@ -203,6 +207,9 @@ namespace Ryujinx.Ava ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter; ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel; ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough; + ConfigurationState.Instance.Graphics.VSyncMode.Event += UpdateVSyncMode; + ConfigurationState.Instance.Graphics.CustomVSyncInterval.Event += UpdateCustomVSyncIntervalValue; + ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Event += UpdateCustomVSyncIntervalEnabled; ConfigurationState.Instance.System.EnableInternetAccess.Event += UpdateEnableInternetAccessState; ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState; @@ -295,6 +302,66 @@ namespace Ryujinx.Ava _renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value); } + public void UpdateVSyncMode(object sender, ReactiveEventArgs e) + { + if (Device != null) + { + Device.VSyncMode = e.NewValue; + Device.UpdateVSyncInterval(); + } + _renderer.Window?.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)e.NewValue); + + _viewModel.ShowCustomVSyncIntervalPicker = (e.NewValue == VSyncMode.Custom); + } + + public void VSyncModeToggle() + { + VSyncMode oldVSyncMode = Device.VSyncMode; + VSyncMode newVSyncMode = VSyncMode.Switch; + bool customVSyncIntervalEnabled = ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Value; + + switch (oldVSyncMode) + { + case VSyncMode.Switch: + newVSyncMode = VSyncMode.Unbounded; + break; + case VSyncMode.Unbounded: + if (customVSyncIntervalEnabled) + { + newVSyncMode = VSyncMode.Custom; + } + else + { + newVSyncMode = VSyncMode.Switch; + } + + break; + case VSyncMode.Custom: + newVSyncMode = VSyncMode.Switch; + break; + } + + UpdateVSyncMode(this, new ReactiveEventArgs(oldVSyncMode, newVSyncMode)); + } + + private void UpdateCustomVSyncIntervalValue(object sender, ReactiveEventArgs e) + { + if (Device != null) + { + Device.TargetVSyncInterval = e.NewValue; + Device.UpdateVSyncInterval(); + } + } + + private void UpdateCustomVSyncIntervalEnabled(object sender, ReactiveEventArgs e) + { + if (Device != null) + { + Device.CustomVSyncIntervalEnabled = e.NewValue; + Device.UpdateVSyncInterval(); + } + } + private void ShowCursor() { Dispatcher.UIThread.Post(() => @@ -352,11 +419,7 @@ namespace Ryujinx.Ava string filename = $"{sanitizedApplicationName}_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png"; - string directory = AppDataManager.Mode switch - { - AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => Path.Combine(AppDataManager.BaseDirPath, "screenshots"), - _ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx"), - }; + string directory = Path.Combine(AppDataManager.BaseDirPath, "screenshots"); string path = Path.Combine(directory, filename); @@ -509,12 +572,6 @@ namespace Ryujinx.Ava Device.Configuration.MultiplayerDisableP2p = e.NewValue; } - public void ToggleVSync() - { - Device.EnableDeviceVsync = !Device.EnableDeviceVsync; - _renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); - } - public void Stop() { _isActive = false; @@ -615,7 +672,7 @@ namespace Ryujinx.Ava _cursorState = CursorStates.ForceChangeCursor; } - public async Task LoadGuestApplication() + public async Task LoadGuestApplication(BlitStruct? customNacpData = null) { InitializeSwitchInstance(); MainWindow.UpdateGraphicsConfig(); @@ -685,7 +742,7 @@ namespace Ryujinx.Ava { Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA)."); - if (!Device.LoadNca(ApplicationPath)) + if (!Device.LoadNca(ApplicationPath, customNacpData)) { Device.Dispose(); @@ -868,7 +925,7 @@ namespace Ryujinx.Ava _viewModel.UiHandler, (SystemLanguage)ConfigurationState.Instance.System.Language.Value, (RegionCode)ConfigurationState.Instance.System.Region.Value, - ConfigurationState.Instance.Graphics.EnableVsync, + ConfigurationState.Instance.Graphics.VSyncMode, ConfigurationState.Instance.System.EnableDockedMode, ConfigurationState.Instance.System.EnablePtc, ConfigurationState.Instance.System.EnableInternetAccess, @@ -885,7 +942,8 @@ namespace Ryujinx.Ava ConfigurationState.Instance.Multiplayer.Mode, ConfigurationState.Instance.Multiplayer.DisableP2p, ConfigurationState.Instance.Multiplayer.LdnPassphrase, - ConfigurationState.Instance.Multiplayer.LdnServer)); + ConfigurationState.Instance.Multiplayer.LdnServer, + ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value)); } private static IHardwareDeviceDriver InitializeAudio() @@ -1006,7 +1064,7 @@ namespace Ryujinx.Ava Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - _renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); + _renderer.Window.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)Device.VSyncMode); while (_isActive) { @@ -1067,6 +1125,7 @@ namespace Ryujinx.Ava { // Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued. string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld]; + string vSyncMode = Device.VSyncMode.ToString(); UpdateShaderCount(); @@ -1076,11 +1135,11 @@ namespace Ryujinx.Ava } StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs( - Device.EnableDeviceVsync, + vSyncMode, LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%", dockedMode, ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), - LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", + $"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %", _displayCount)); } @@ -1179,8 +1238,16 @@ namespace Ryujinx.Ava { switch (currentHotkeyState) { - case KeyboardHotkeyState.ToggleVSync: - ToggleVSync(); + case KeyboardHotkeyState.ToggleVSyncMode: + VSyncModeToggle(); + break; + case KeyboardHotkeyState.CustomVSyncIntervalDecrement: + Device.DecrementCustomVSyncInterval(); + _viewModel.CustomVSyncInterval -= 1; + break; + case KeyboardHotkeyState.CustomVSyncIntervalIncrement: + Device.IncrementCustomVSyncInterval(); + _viewModel.CustomVSyncInterval += 1; break; case KeyboardHotkeyState.Screenshot: ScreenshotRequested = true; @@ -1267,9 +1334,9 @@ namespace Ryujinx.Ava { KeyboardHotkeyState state = KeyboardHotkeyState.None; - if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVsync)) + if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVSyncMode)) { - state = KeyboardHotkeyState.ToggleVSync; + state = KeyboardHotkeyState.ToggleVSyncMode; } else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot)) { @@ -1303,6 +1370,14 @@ namespace Ryujinx.Ava { state = KeyboardHotkeyState.VolumeDown; } + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CustomVSyncIntervalIncrement)) + { + state = KeyboardHotkeyState.CustomVSyncIntervalIncrement; + } + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CustomVSyncIntervalDecrement)) + { + state = KeyboardHotkeyState.CustomVSyncIntervalDecrement; + } return state; } diff --git a/src/Ryujinx/Assets/Locales/ar_SA.json b/src/Ryujinx/Assets/Locales/ar_SA.json index 781568fee..056dbfedb 100644 --- a/src/Ryujinx/Assets/Locales/ar_SA.json +++ b/src/Ryujinx/Assets/Locales/ar_SA.json @@ -1,6 +1,7 @@ { "Language": "اَلْعَرَبِيَّةُ", "MenuBarFileOpenApplet": "فتح التطبيق المصغر", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "‫افتح تطبيق تحرير Mii في الوضع المستقل", "SettingsTabInputDirectMouseAccess": "الوصول المباشر للفأرة", "SettingsTabSystemMemoryManagerMode": "وضع إدارة الذاكرة:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "تثبيت البرنامج الثابت", "MenuBarFileToolsInstallFirmwareFromFile": "تثبيت برنامج ثابت من XCI أو ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "تثبيت برنامج ثابت من مجلد", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "إدارة أنواع الملفات", "MenuBarToolsInstallFileTypes": "تثبيت أنواع الملفات", "MenuBarToolsUninstallFileTypes": "إزالة أنواع الملفات", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_عرض", "MenuBarViewWindow": "حجم النافذة", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_مساعدة", "MenuBarHelpCheckForUpdates": "تحقق من التحديثات", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "حول", "MenuSearch": "بحث...", "GameListHeaderFavorite": "مفضلة", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "يفتح المجلد الذي يحتوي على تعديلات‫(mods) التطبيق", "GameListContextMenuOpenSdModsDirectory": "فتح مجلد تعديلات‫(mods) أتموسفير", "GameListContextMenuOpenSdModsDirectoryToolTip": "يفتح مجلد أتموسفير لبطاقة SD البديلة الذي يحتوي على تعديلات التطبيق. مفيد للتعديلات التي تم تعبئتها للأجهزة الحقيقية.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} لعبة تم تحميلها", "StatusBarSystemVersion": "إصدار النظام: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "الحد الأدنى لتعيينات الذاكرة المكتشفة", "LinuxVmMaxMapCountDialogTextPrimary": "هل ترغب في زيادة قيمة vm.max_map_count إلى {0}", "LinuxVmMaxMapCountDialogTextSecondary": "قد تحاول بعض الألعاب إنشاء المزيد من تعيينات الذاكرة أكثر مما هو مسموح به حاليا. سيغلق ريوجينكس بمجرد تجاوز هذا الحد.", @@ -400,6 +414,8 @@ "InputDialogTitle": "حوار الإدخال", "InputDialogOk": "موافق", "InputDialogCancel": "إلغاء", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "اختر اسم الملف الشخصي", "InputDialogAddNewProfileHeader": "الرجاء إدخال اسم الملف الشخصي", "InputDialogAddNewProfileSubtext": "(الطول الأقصى: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "جاري استخراج التحديث...", "DialogUpdaterRenamingMessage": "إعادة تسمية التحديث...", "DialogUpdaterAddingFilesMessage": "إضافة تحديث جديد...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "اكتمل التحديث", "DialogUpdaterRestartMessage": "هل تريد إعادة تشغيل ريوجينكس الآن؟", "DialogUpdaterNoInternetMessage": "أنت غير متصل بالإنترنت.", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "تم إلغاء تثبيت أنواع الملفات بنجاح!", "DialogUninstallFileTypesErrorMessage": "فشل إلغاء تثبيت أنواع الملفات.", "DialogOpenSettingsWindowLabel": "فتح نافذة الإعدادات", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "تطبيق وحدة التحكم المصغر", "DialogMessageDialogErrorExceptionMessage": "خطأ في عرض مربع حوار الرسالة: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "خطأ في عرض لوحة مفاتيح البرامج: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\nهل تريد المتابعة؟", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "تثبيت البرنامج الثابت...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "تم تثبيت إصدار النظام {0} بنجاح.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "لن تكون هناك ملفات الشخصية أخرى لفتحها إذا تم حذف الملف الشخصي المحدد", "DialogUserProfileDeletionConfirmMessage": "هل تريد حذف الملف الشخصي المحدد", "DialogUserProfileUnsavedChangesTitle": "تحذير - التغييرات غير محفوظة", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "انقر لفتح موقع ريوجينكس في متصفحك الافتراضي.", "AboutDisclaimerMessage": "ريوجينكس لا ينتمي إلى نينتندو™،\nأو أي من شركائها بأي شكل من الأشكال.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) يتم \nاستخدامه في محاكاة أمبيو لدينا.", - "AboutPatreonUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في باتريون في متصفحك الافتراضي.", "AboutGithubUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في غيت هاب في متصفحك الافتراضي.", "AboutDiscordUrlTooltipMessage": "انقر لفتح دعوة إلى خادم ريوجينكس في ديكسورد في متصفحك الافتراضي.", - "AboutTwitterUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في تويتر في متصفحك الافتراضي.", "AboutRyujinxAboutTitle": "حول:", - "AboutRyujinxAboutContent": "ريوجينكس هو محاكي لجهاز نينتندو سويتش™.\nمن فضلك ادعمنا على باتريون.\nاحصل على آخر الأخبار على تويتر أو ديسكورد.\nيمكن للمطورين المهتمين بالمساهمة معرفة المزيد على غيت هاب أو ديسكورد.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "تتم صيانته بواسطة:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "انقر لفتح صفحة المساهمين في متصفحك الافتراضي.", - "AboutRyujinxSupprtersTitle": "مدعوم على باتريون بواسطة:", "AmiiboSeriesLabel": "مجموعة أميبو", "AmiiboCharacterLabel": "شخصية", "AmiiboScanButtonLabel": "فحصه", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "الإصدار: {0}", "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "ريوجينكس - معلومات", "RyujinxConfirm": "ريوجينكس - تأكيد", "FileDialogAllTypes": "كل الأنواع", "Never": "مطلقا", "SwkbdMinCharacters": "يجب أن يبلغ طوله {0} حرفا على الأقل", "SwkbdMinRangeCharacters": "يجب أن يتكون من {0}-{1} حرفا", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "لوحة المفاتيح البرمجية", "SoftwareKeyboardModeNumeric": "يجب أن يكون 0-9 أو '.' فقط", "SoftwareKeyboardModeAlphabet": "يجب أن تكون الأحرف غير CJK فقط", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "إضافة ملفات جديدة...", "UpdaterExtracting": "استخراج التحديث...", "UpdaterDownloading": "تحميل التحديث...", - "Game": "لعبة", "Docked": "تركيب بالمنصة", "Handheld": "محمول", "ConnectionError": "خطأ في الاتصال", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "حدد ملفات المحتوي الإضافي", "SelectUpdateDialogTitle": "حدد ملفات التحديث", "SelectModDialogTitle": "حدد مجلد التعديل", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "مدير الملفات الشخصية للمستخدمين", "CheatWindowTitle": "مدير الغش", "DlcWindowTitle": "إدارة المحتوى القابل للتنزيل لـ {0} ({1})", "ModWindowTitle": "إدارة التعديلات لـ {0} ({1})", "UpdateWindowTitle": "مدير تحديث العنوان", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", @@ -735,7 +792,7 @@ "CheatWindowHeading": "الغش متوفر لـ {0} [{1}]", "BuildId": "معرف البناء:", "DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.", - "DlcWindowHeading": "المحتويات القابلة للتنزيل {0}", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "{0} تعديل", "UserProfilesEditProfile": "تعديل المحدد", + "Continue": "Continue", "Cancel": "إلغاء", "Save": "حفظ", "Discard": "تجاهل", @@ -810,5 +868,17 @@ "MultiplayerMode": "الوضع:", "MultiplayerModeTooltip": "تغيير وضع LDN متعدد اللاعبين.\n\nسوف يقوم LdnMitm بتعديل وظيفة اللعب المحلية/اللاسلكية المحلية في الألعاب لتعمل كما لو كانت شبكة LAN، مما يسمح باتصالات الشبكة المحلية نفسها مع محاكيات ريوجينكس الأخرى وأجهزة نينتندو سويتش المخترقة التي تم تثبيت وحدة ldn_mitm عليها.\n\nيتطلب وضع اللاعبين المتعددين أن يكون جميع اللاعبين على نفس إصدار اللعبة (على سبيل المثال، يتعذر على الإصدار 13.0.1 من سوبر سماش برذرز ألتميت الاتصال بالإصدار 13.0.0).\n\nاتركه معطلا إذا لم تكن متأكدا.", "MultiplayerModeDisabled": "معطل", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/de_DE.json b/src/Ryujinx/Assets/Locales/de_DE.json index c6f9768c6..e93098fca 100644 --- a/src/Ryujinx/Assets/Locales/de_DE.json +++ b/src/Ryujinx/Assets/Locales/de_DE.json @@ -1,6 +1,7 @@ { "Language": "Deutsch", "MenuBarFileOpenApplet": "Öffne Anwendung", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Öffnet das Mii-Editor-Applet im Standalone-Modus", "SettingsTabInputDirectMouseAccess": "Direkter Mauszugriff", "SettingsTabSystemMemoryManagerMode": "Speichermanagermodus:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "Firmware installieren", "MenuBarFileToolsInstallFirmwareFromFile": "Firmware von einer XCI- oder einer ZIP-Datei installieren", "MenuBarFileToolsInstallFirmwareFromDirectory": "Firmware aus einem Verzeichnis installieren", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Dateitypen verwalten", "MenuBarToolsInstallFileTypes": "Dateitypen installieren", "MenuBarToolsUninstallFileTypes": "Dateitypen deinstallieren", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_Ansicht", "MenuBarViewWindow": "Fenstergröße", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Hilfe", "MenuBarHelpCheckForUpdates": "Nach Updates suchen", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "Über Ryujinx", "MenuSearch": "Suchen...", "GameListHeaderFavorite": "Favorit", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "Öffnet das Verzeichnis, welches Mods für die Spiele beinhaltet", "GameListContextMenuOpenSdModsDirectory": "Atmosphere-Mod-Verzeichnis öffnen", "GameListContextMenuOpenSdModsDirectoryToolTip": "Öffnet das alternative SD-Karten-Atmosphere-Verzeichnis, das die Mods der Anwendung enthält. Dieser Ordner ist nützlich für Mods, die für echte Hardware erstellt worden sind.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} Spiele geladen", "StatusBarSystemVersion": "Systemversion: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "Niedriges Limit für Speicherzuordnungen erkannt", "LinuxVmMaxMapCountDialogTextPrimary": "Möchtest Du den Wert von vm.max_map_count auf {0} erhöhen", "LinuxVmMaxMapCountDialogTextSecondary": "Einige Spiele könnten versuchen, mehr Speicherzuordnungen zu erstellen, als derzeit erlaubt. Ryujinx wird abstürzen, sobald dieses Limit überschritten wird.", @@ -400,6 +414,8 @@ "InputDialogTitle": "Eingabe-Dialog", "InputDialogOk": "OK", "InputDialogCancel": "Abbrechen", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "Wähle den Profilnamen", "InputDialogAddNewProfileHeader": "Bitte gebe einen Profilnamen ein", "InputDialogAddNewProfileSubtext": "(Maximale Länge: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Update wird entpackt...", "DialogUpdaterRenamingMessage": "Update wird umbenannt...", "DialogUpdaterAddingFilesMessage": "Update wird hinzugefügt...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Update abgeschlossen!", "DialogUpdaterRestartMessage": "Ryujinx jetzt neu starten?", "DialogUpdaterNoInternetMessage": "Es besteht keine Verbindung mit dem Internet!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "Dateitypen erfolgreich deinstalliert!", "DialogUninstallFileTypesErrorMessage": "Deinstallation der Dateitypen fehlgeschlagen.", "DialogOpenSettingsWindowLabel": "Fenster-Einstellungen öffnen", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "Controller-Applet", "DialogMessageDialogErrorExceptionMessage": "Fehler bei der Anzeige des Meldungs-Dialogs: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Fehler bei der Anzeige der Software-Tastatur: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nMöchtest du fortfahren?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Firmware wird installiert...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Systemversion {0} wurde erfolgreich installiert.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Es können keine anderen Profile geöffnet werden, wenn das ausgewählte Profil gelöscht wird.", "DialogUserProfileDeletionConfirmMessage": "Möchtest du das ausgewählte Profil löschen?", "DialogUserProfileUnsavedChangesTitle": "Warnung - Nicht gespeicherte Änderungen", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "Klicke hier, um die Ryujinx Website im Standardbrowser zu öffnen.", "AboutDisclaimerMessage": "Ryujinx ist in keinster Weise weder mit Nintendo™, \nnoch mit deren Partnern verbunden.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) wird in unserer Amiibo \nEmulation benutzt.", - "AboutPatreonUrlTooltipMessage": "Klicke hier, um die Ryujinx Patreon Seite im Standardbrowser zu öffnen.", "AboutGithubUrlTooltipMessage": "Klicke hier, um die Ryujinx GitHub Seite im Standardbrowser zu öffnen.", "AboutDiscordUrlTooltipMessage": "Klicke hier, um eine Einladung zum Ryujinx Discord Server im Standardbrowser zu öffnen.", - "AboutTwitterUrlTooltipMessage": "Klicke hier, um die Ryujinx Twitter Seite im Standardbrowser zu öffnen.", "AboutRyujinxAboutTitle": "Über:", - "AboutRyujinxAboutContent": "Ryujinx ist ein Nintendo Switch™ Emulator.\nBitte unterstütze uns auf Patreon.\nAuf Twitter oder Discord erfährst du alle Neuigkeiten.\nEntwickler, die an einer Mitarbeit interessiert sind, können auf GitHub oder Discord mehr erfahren.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Entwickelt von:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Klicke hier, um die Liste der Mitwirkenden im Standardbrowser zu öffnen.", - "AboutRyujinxSupprtersTitle": "Unterstützt auf Patreon von:", "AmiiboSeriesLabel": "Amiibo-Serie", "AmiiboCharacterLabel": "Charakter", "AmiiboScanButtonLabel": "Einscannen", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "Version {0} - {1}", "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - Info", "RyujinxConfirm": "Ryujinx - Bestätigung", "FileDialogAllTypes": "Alle Typen", "Never": "Niemals", "SwkbdMinCharacters": "Muss mindestens {0} Zeichen lang sein", "SwkbdMinRangeCharacters": "Muss {0}-{1} Zeichen lang sein", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Software-Tastatur", "SoftwareKeyboardModeNumeric": "Darf nur 0-9 oder \".\" sein", "SoftwareKeyboardModeAlphabet": "Keine CJK-Zeichen", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "Neue Dateien hinzufügen...", "UpdaterExtracting": "Update extrahieren...", "UpdaterDownloading": "Update herunterladen...", - "Game": "Spiel", "Docked": "Docked", "Handheld": "Handheld", "ConnectionError": "Verbindungsfehler.", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "DLC-Dateien auswählen", "SelectUpdateDialogTitle": "Update-Datei auswählen", "SelectModDialogTitle": "Mod-Ordner auswählen", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "Benutzerprofile verwalten", "CheatWindowTitle": "Spiel-Cheats verwalten", "DlcWindowTitle": "Spiel-DLC verwalten", "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Spiel-Updates verwalten", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", @@ -735,7 +792,7 @@ "CheatWindowHeading": "Cheats verfügbar für {0} [{1}]", "DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.", "BuildId": "BuildId:", - "DlcWindowHeading": "DLC verfügbar für {0} [{1}]", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Profil bearbeiten", + "Continue": "Continue", "Cancel": "Abbrechen", "Save": "Speichern", "Discard": "Verwerfen", @@ -810,5 +868,17 @@ "MultiplayerMode": "Modus:", "MultiplayerModeTooltip": "Ändert den LDN-Mehrspielermodus.\n\nLdnMitm ändert die lokale drahtlose/lokale Spielfunktionalität in Spielen so, dass sie wie ein LAN funktioniert und lokale, netzwerkgleiche Verbindungen mit anderen Ryujinx-Instanzen und gehackten Nintendo Switch-Konsolen ermöglicht, auf denen das ldn_mitm-Modul installiert ist.\n\nMultiplayer erfordert, dass alle Spieler die gleiche Spielversion verwenden (d.h. Super Smash Bros. Ultimate v13.0.1 kann sich nicht mit v13.0.0 verbinden).\n\nIm Zweifelsfall auf DISABLED lassen.", "MultiplayerModeDisabled": "Deaktiviert", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/el_GR.json b/src/Ryujinx/Assets/Locales/el_GR.json index 76049fc3f..5720fe689 100644 --- a/src/Ryujinx/Assets/Locales/el_GR.json +++ b/src/Ryujinx/Assets/Locales/el_GR.json @@ -1,6 +1,7 @@ { "Language": "Ελληνικά", "MenuBarFileOpenApplet": "Άνοιγμα Applet", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Άνοιγμα του Mii Editor Applet σε Αυτόνομη λειτουργία", "SettingsTabInputDirectMouseAccess": "Άμεση Πρόσβαση Ποντικιού", "SettingsTabSystemMemoryManagerMode": "Λειτουργία Διαχείρισης Μνήμης:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "Εγκατάσταση Firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Εγκατάσταση Firmware από XCI ή ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Εγκατάσταση Firmware από τοποθεσία", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Διαχείριση τύπων αρχείων", "MenuBarToolsInstallFileTypes": "Εγκαταστήσετε τύπους αρχείων.", "MenuBarToolsUninstallFileTypes": "Απεγκαταστήσετε τύπους αρχείων", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_View", "MenuBarViewWindow": "Window Size", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Βοήθεια", "MenuBarHelpCheckForUpdates": "Έλεγχος για Ενημερώσεις", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "Σχετικά με", "MenuSearch": "Αναζήτηση...", "GameListHeaderFavorite": "Αγαπημένο", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods", "GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory", "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} Φορτωμένα Παιχνίδια", "StatusBarSystemVersion": "Έκδοση Συστήματος: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "Εντοπίστηκε χαμηλό όριο για αντιστοιχίσεις μνήμης", "LinuxVmMaxMapCountDialogTextPrimary": "Θα θέλατε να αυξήσετε την τιμή του vm.max_map_count σε {0}", "LinuxVmMaxMapCountDialogTextSecondary": "Μερικά παιχνίδια μπορεί να προσπαθήσουν να δημιουργήσουν περισσότερες αντιστοιχίσεις μνήμης από αυτές που επιτρέπονται τώρα. Ο Ryujinx θα καταρρεύσει μόλις ξεπεραστεί αυτό το όριο.", @@ -400,6 +414,8 @@ "InputDialogTitle": "Διάλογος Εισαγωγής", "InputDialogOk": "ΟΚ", "InputDialogCancel": "Ακύρωση", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "Επιλογή Ονόματος Προφίλ", "InputDialogAddNewProfileHeader": "Εισαγωγή Ονόματος Προφίλ", "InputDialogAddNewProfileSubtext": "(Σύνολο Χαρακτήρων: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Εξαγωγή Ενημέρωσης...", "DialogUpdaterRenamingMessage": "Μετονομασία Ενημέρωσης...", "DialogUpdaterAddingFilesMessage": "Προσθήκη Νέας Ενημέρωσης...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Η Ενημέρωση Ολοκληρώθηκε!", "DialogUpdaterRestartMessage": "Θέλετε να επανεκκινήσετε το Ryujinx τώρα;", "DialogUpdaterNoInternetMessage": "Δεν είστε συνδεδεμένοι στο Διαδίκτυο!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "Επιτυχής απεγκατάσταση τύπων αρχείων!", "DialogUninstallFileTypesErrorMessage": "Αποτυχία απεγκατάστασης τύπων αρχείων.", "DialogOpenSettingsWindowLabel": "Άνοιγμα Παραθύρου Ρυθμίσεων", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "Applet Χειρισμού", "DialogMessageDialogErrorExceptionMessage": "Σφάλμα εμφάνισης του διαλόγου Μηνυμάτων: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Σφάλμα εμφάνισης Λογισμικού Πληκτρολογίου: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nΘέλετε να συνεχίσετε;", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Εγκατάσταση Firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Η έκδοση συστήματος {0} εγκαταστάθηκε με επιτυχία.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Δεν θα υπάρχουν άλλα προφίλ εάν διαγραφεί το επιλεγμένο", "DialogUserProfileDeletionConfirmMessage": "Θέλετε να διαγράψετε το επιλεγμένο προφίλ", "DialogUserProfileUnsavedChangesTitle": "Προσοχή - Μην Αποθηκευμένες Αλλαγές.", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τον ιστότοπο Ryujinx στο προεπιλεγμένο πρόγραμμα περιήγησης.", "AboutDisclaimerMessage": "Το Ryujinx δεν είναι συνδεδεμένο με τη Nintendo™,\nούτε με κανέναν από τους συνεργάτες της, με οποιονδήποτε τρόπο.", "AboutAmiiboDisclaimerMessage": "Το AmiiboAPI (www.amiiboapi.com) χρησιμοποιείται\nστην προσομοίωση Amiibo.", - "AboutPatreonUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx Patreon στο προεπιλεγμένο πρόγραμμα περιήγησης.", "AboutGithubUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx GitHub στο προεπιλεγμένο πρόγραμμα περιήγησης.", "AboutDiscordUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε μία πρόσκληση στον διακομιστή Ryujinx Discord στο προεπιλεγμένο πρόγραμμα περιήγησης.", - "AboutTwitterUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx Twitter στο προεπιλεγμένο πρόγραμμα περιήγησης.", "AboutRyujinxAboutTitle": "Σχετικά με:", - "AboutRyujinxAboutContent": "Το Ryujinx είναι ένας εξομοιωτής για το Nintendo Switch™.\nΥποστηρίξτε μας στο Patreon.\nΛάβετε όλα τα τελευταία νέα στο Twitter ή στο Discord.\nΟι προγραμματιστές που ενδιαφέρονται να συνεισφέρουν μπορούν να μάθουν περισσότερα στο GitHub ή στο Discord μας.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Συντηρείται από:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Συνεισφέροντες στο προεπιλεγμένο πρόγραμμα περιήγησης.", - "AboutRyujinxSupprtersTitle": "Υποστηρίζεται στο Patreon από:", "AmiiboSeriesLabel": "Σειρά Amiibo", "AmiiboCharacterLabel": "Χαρακτήρας", "AmiiboScanButtonLabel": "Σαρώστε το", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "Version {0} - {1}", "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - Πληροφορίες", "RyujinxConfirm": "Ryujinx - Επιβεβαίωση", "FileDialogAllTypes": "Όλοι οι τύποι", "Never": "Ποτέ", "SwkbdMinCharacters": "Πρέπει να έχει μήκος τουλάχιστον {0} χαρακτήρες", "SwkbdMinRangeCharacters": "Πρέπει να έχει μήκος {0}-{1} χαρακτήρες", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Εικονικό Πληκτρολόγιο", "SoftwareKeyboardModeNumeric": "Πρέπει να είναι 0-9 ή '.' μόνο", "SoftwareKeyboardModeAlphabet": "Πρέπει να μην είναι μόνο χαρακτήρες CJK", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "Προσθήκη Νέων Αρχείων...", "UpdaterExtracting": "Εξαγωγή Ενημέρωσης...", "UpdaterDownloading": "Λήψη Ενημέρωσης...", - "Game": "Παιχνίδι", "Docked": "Προσκολλημένο", "Handheld": "Χειροκίνητο", "ConnectionError": "Σφάλμα Σύνδεσης.", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "Επιλογή αρχείων DLC", "SelectUpdateDialogTitle": "Επιλογή αρχείων ενημέρωσης", "SelectModDialogTitle": "Select mod directory", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "Διαχειριστής Προφίλ Χρήστη", "CheatWindowTitle": "Διαχειριστής των Cheats", "DlcWindowTitle": "Downloadable Content Manager", "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Διαχειριστής Ενημερώσεων Τίτλου", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", @@ -735,7 +792,7 @@ "CheatWindowHeading": "Διαθέσιμα Cheats για {0} [{1}]", "BuildId": "BuildId:", "DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.", - "DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Επεξεργασία Επιλεγμένων", + "Continue": "Continue", "Cancel": "Ακύρωση", "Save": "Αποθήκευση", "Discard": "Απόρριψη", @@ -810,5 +868,17 @@ "MultiplayerMode": "Λειτουργία:", "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", "MultiplayerModeDisabled": "Disabled", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/en_US.json b/src/Ryujinx/Assets/Locales/en_US.json index 9354c8a41..a984b6cda 100644 --- a/src/Ryujinx/Assets/Locales/en_US.json +++ b/src/Ryujinx/Assets/Locales/en_US.json @@ -1,6 +1,7 @@ { "Language": "English (US)", "MenuBarFileOpenApplet": "Open Applet", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Open Mii Editor Applet in Standalone mode", "SettingsTabInputDirectMouseAccess": "Direct Mouse Access", "SettingsTabSystemMemoryManagerMode": "Memory Manager Mode:", @@ -30,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Install Firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Install a firmware from XCI or ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Install a firmware from a directory", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Manage file types", "MenuBarToolsInstallFileTypes": "Install file types", "MenuBarToolsUninstallFileTypes": "Uninstall file types", @@ -40,6 +44,12 @@ "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Help", "MenuBarHelpCheckForUpdates": "Check for Updates", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "About", "MenuSearch": "Search...", "GameListHeaderFavorite": "Fav", @@ -142,9 +152,20 @@ "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Latin American Spanish", "SettingsTabSystemSystemLanguageSimplifiedChinese": "Simplified Chinese", "SettingsTabSystemSystemLanguageTraditionalChinese": "Traditional Chinese", - "SettingsTabSystemSystemTimeZone": "System TimeZone:", + "SettingsTabSystemSystemTimeZone": "System Time Zone:", "SettingsTabSystemSystemTime": "System Time:", - "SettingsTabSystemEnableVsync": "VSync", + "SettingsTabSystemVSyncMode": "VSync:", + "SettingsTabSystemEnableCustomVSyncInterval": "Enable custom refresh rate (Experimental)", + "SettingsTabSystemVSyncModeSwitch": "Switch", + "SettingsTabSystemVSyncModeUnbounded": "Unbounded", + "SettingsTabSystemVSyncModeCustom": "Custom Refresh Rate", + "SettingsTabSystemVSyncModeTooltip": "Emulated Vertical Sync. 'Switch' emulates the Switch's refresh rate of 60Hz. 'Unbounded' is an unbounded refresh rate.", + "SettingsTabSystemVSyncModeTooltipCustom": "Emulated Vertical Sync. 'Switch' emulates the Switch's refresh rate of 60Hz. 'Unbounded' is an unbounded refresh rate. 'Custom' emulates the specified custom refresh rate.", + "SettingsTabSystemEnableCustomVSyncIntervalTooltip": "Allows the user to specify an emulated refresh rate. In some titles, this may speed up or slow down the rate of gameplay logic. In other titles, it may allow for capping FPS at some multiple of the refresh rate, or lead to unpredictable behavior. This is an experimental feature, with no guarantees for how gameplay will be affected. \n\nLeave OFF if unsure.", + "SettingsTabSystemCustomVSyncIntervalValueTooltip": "The custom refresh rate target value.", + "SettingsTabSystemCustomVSyncIntervalSliderTooltip": "The custom refresh rate, as a percentage of the normal Switch refresh rate.", + "SettingsTabSystemCustomVSyncIntervalPercentage": "Custom Refresh Rate %:", + "SettingsTabSystemCustomVSyncIntervalValue": "Custom Refresh Rate Value:", "SettingsTabSystemEnablePptc": "PPTC (Profiled Persistent Translation Cache)", "SettingsTabSystemEnableLowPowerPptc": "Low-power PPTC cache", "SettingsTabSystemEnableFsIntegrityChecks": "FS Integrity Checks", @@ -153,6 +174,7 @@ "SettingsTabSystemAudioBackendOpenAL": "OpenAL", "SettingsTabSystemAudioBackendSoundIO": "SoundIO", "SettingsTabSystemAudioBackendSDL2": "SDL2", + "SettingsTabSystemCustomVSyncInterval": "Interval", "SettingsTabSystemHacks": "Hacks", "SettingsTabSystemHacksNote": "May cause instability", "SettingsTabSystemDramSize": "DRAM size:", @@ -457,6 +479,7 @@ "DialogUpdaterExtractionMessage": "Extracting Update...", "DialogUpdaterRenamingMessage": "Renaming Update...", "DialogUpdaterAddingFilesMessage": "Adding New Update...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Update Complete!", "DialogUpdaterRestartMessage": "Do you want to restart Ryujinx now?", "DialogUpdaterNoInternetMessage": "You are not connected to the Internet!", @@ -504,6 +527,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nDo you want to continue?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installing firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "System version {0} successfully installed.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "There would be no other profiles to be opened if selected profile is deleted", "DialogUserProfileDeletionConfirmMessage": "Do you want to delete the selected profile", "DialogUserProfileUnsavedChangesTitle": "Warning - Unsaved Changes", @@ -540,15 +570,13 @@ "AboutUrlTooltipMessage": "Click to open the Ryujinx website in your default browser.", "AboutDisclaimerMessage": "Ryujinx is not affiliated with Nintendo™,\nor any of its partners, in any way.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) is used\nin our Amiibo emulation.", - "AboutPatreonUrlTooltipMessage": "Click to open the Ryujinx Patreon page in your default browser.", "AboutGithubUrlTooltipMessage": "Click to open the Ryujinx GitHub page in your default browser.", "AboutDiscordUrlTooltipMessage": "Click to open an invite to the Ryujinx Discord server in your default browser.", - "AboutTwitterUrlTooltipMessage": "Click to open the Ryujinx Twitter page in your default browser.", "AboutRyujinxAboutTitle": "About:", - "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nPlease support us on Patreon.\nGet all the latest news on our Twitter or Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Maintained By:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Click to open the Contributors page in your default browser.", - "AboutRyujinxSupprtersTitle": "Supported on Patreon By:", "AmiiboSeriesLabel": "Amiibo Series", "AmiiboCharacterLabel": "Character", "AmiiboScanButtonLabel": "Scan It", @@ -690,6 +718,9 @@ "Never": "Never", "SwkbdMinCharacters": "Must be at least {0} characters long", "SwkbdMinRangeCharacters": "Must be {0}-{1} characters long", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Software Keyboard", "SoftwareKeyboardModeNumeric": "Must be 0-9 or '.' only", "SoftwareKeyboardModeAlphabet": "Must be non CJK-characters only", @@ -703,7 +734,6 @@ "UpdaterAddingFiles": "Adding New Files...", "UpdaterExtracting": "Extracting Update...", "UpdaterDownloading": "Downloading Update...", - "Game": "Game", "Docked": "Docked", "Handheld": "Handheld", "ConnectionError": "Connection Error.", @@ -719,11 +749,13 @@ "RyujinxUpdater": "Ryujinx Updater", "SettingsTabHotkeys": "Keyboard Hotkeys", "SettingsTabHotkeysHotkeys": "Keyboard Hotkeys", - "SettingsTabHotkeysToggleVsyncHotkey": "Toggle VSync:", + "SettingsTabHotkeysToggleVSyncModeHotkey": "Toggle VSync mode:", "SettingsTabHotkeysScreenshotHotkey": "Screenshot:", "SettingsTabHotkeysShowUiHotkey": "Show UI:", "SettingsTabHotkeysPauseHotkey": "Pause:", "SettingsTabHotkeysToggleMuteHotkey": "Mute:", + "SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey": "Raise custom refresh rate", + "SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey": "Lower custom refresh rate", "ControllerMotionTitle": "Motion Control Settings", "ControllerRumbleTitle": "Rumble Settings", "SettingsSelectThemeFileDialogTitle": "Select Theme File", @@ -774,7 +806,7 @@ "CheatWindowHeading": "Cheats Available for {0} [{1}]", "BuildId": "BuildId:", "DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.", - "DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", diff --git a/src/Ryujinx/Assets/Locales/es_ES.json b/src/Ryujinx/Assets/Locales/es_ES.json index cf5c586d0..f6ed8b379 100644 --- a/src/Ryujinx/Assets/Locales/es_ES.json +++ b/src/Ryujinx/Assets/Locales/es_ES.json @@ -1,6 +1,7 @@ { "Language": "Español (ES)", "MenuBarFileOpenApplet": "Abrir applet", + "MenuBarFileOpenAppletOpenMiiApplet": "Applet Editor Mii", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abre el editor de Mii en modo autónomo", "SettingsTabInputDirectMouseAccess": "Acceso directo al ratón", "SettingsTabSystemMemoryManagerMode": "Modo del administrador de memoria:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "Instalar firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Instalar firmware desde un archivo XCI o ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Instalar firmware desde una carpeta", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Instalar keys de KEYS o ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Instalar keys de un directorio", "MenuBarToolsManageFileTypes": "Administrar tipos de archivo", "MenuBarToolsInstallFileTypes": "Instalar tipos de archivo", "MenuBarToolsUninstallFileTypes": "Desinstalar tipos de archivo", + "MenuBarToolsXCITrimmer": "Recortar archivos XCI", "MenuBarView": "_View", "MenuBarViewWindow": "Tamaño Ventana", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Ayuda", "MenuBarHelpCheckForUpdates": "Buscar actualizaciones", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "Acerca de", "MenuSearch": "Buscar...", "GameListHeaderFavorite": "Favoritos", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "Abre el directorio que contiene los Mods de la Aplicación.", "GameListContextMenuOpenSdModsDirectory": "Abrir Directorio de Mods de Atmosphere\n\n\n\n\n\n", "GameListContextMenuOpenSdModsDirectoryToolTip": "Abre el directorio alternativo de la tarjeta SD de Atmosphere que contiene los Mods de la Aplicación. Útil para los mods que están empaquetados para el hardware real.", + "GameListContextMenuTrimXCI": "Verificar y recortar archivo XCI", + "GameListContextMenuTrimXCIToolTip": "Verificar y recortar archivo XCI para ahorrar espacio en disco", "StatusBarGamesLoaded": "{0}/{1} juegos cargados", "StatusBarSystemVersion": "Versión del sistema: {0}", + "StatusBarXCIFileTrimming": "Recortando el siguiente archivo XCI: '{0}'", "LinuxVmMaxMapCountDialogTitle": "Límite inferior para mapeos de memoria detectado", "LinuxVmMaxMapCountDialogTextPrimary": "¿Quieres aumentar el valor de vm.max_map_count a {0}?", "LinuxVmMaxMapCountDialogTextSecondary": "Algunos juegos podrían intentar crear más mapeos de memoria de los permitidos. Ryujinx se bloqueará tan pronto como se supere este límite.", @@ -400,6 +414,8 @@ "InputDialogTitle": "Cuadro de diálogo de entrada", "InputDialogOk": "Aceptar", "InputDialogCancel": "Cancelar", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "Introducir nombre de perfil", "InputDialogAddNewProfileHeader": "Por favor elige un nombre de usuario", "InputDialogAddNewProfileSubtext": "(Máximo de caracteres: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Extrayendo actualización...", "DialogUpdaterRenamingMessage": "Renombrando actualización...", "DialogUpdaterAddingFilesMessage": "Aplicando actualización...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "¡Actualización completa!", "DialogUpdaterRestartMessage": "¿Quieres reiniciar Ryujinx?", "DialogUpdaterNoInternetMessage": "¡No estás conectado a internet!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "¡Tipos de archivos desinstalados con éxito!", "DialogUninstallFileTypesErrorMessage": "No se pudo desinstalar los tipos de archivo.", "DialogOpenSettingsWindowLabel": "Abrir ventana de opciones", + "DialogOpenXCITrimmerWindowLabel": "Ventana recortador XCI", "DialogControllerAppletTitle": "Applet de mandos", "DialogMessageDialogErrorExceptionMessage": "Error al mostrar cuadro de diálogo: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Error al mostrar teclado de software: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n¿Continuar?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Instalando firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Versión de sistema {0} instalada con éxito.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "Se halló un archivo Keys inválido en {0}", + "DialogKeysInstallerKeysInstallTitle": "Instalar Keys", + "DialogKeysInstallerKeysInstallMessage": "Un nuevo archivo Keys será instalado.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nEsto puede reemplazar algunas de las Keys actualmente instaladas.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDeseas continuar?", + "DialogKeysInstallerKeysInstallWaitMessage": "Instalando Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "Nuevo archivo Keys instalado con éxito.", "DialogUserProfileDeletionWarningMessage": "Si eliminas el perfil seleccionado no quedará ningún otro perfil", "DialogUserProfileDeletionConfirmMessage": "¿Quieres eliminar el perfil seleccionado?", "DialogUserProfileUnsavedChangesTitle": "Advertencia - Cambios sin guardar", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "Haz clic para abrir el sitio web de Ryujinx en tu navegador predeterminado.", "AboutDisclaimerMessage": "Ryujinx no tiene afiliación alguna con Nintendo™,\nni con ninguno de sus socios.", "AboutAmiiboDisclaimerMessage": "Utilizamos AmiiboAPI (www.amiiboapi.com)\nen nuestra emulación de Amiibo.", - "AboutPatreonUrlTooltipMessage": "Haz clic para abrir el Patreon de Ryujinx en tu navegador predeterminado.", "AboutGithubUrlTooltipMessage": "Haz clic para abrir el GitHub de Ryujinx en tu navegador predeterminado.", "AboutDiscordUrlTooltipMessage": "Haz clic para recibir una invitación al Discord de Ryujinx en tu navegador predeterminado.", - "AboutTwitterUrlTooltipMessage": "Haz clic para abrir el Twitter de Ryujinx en tu navegador predeterminado.", "AboutRyujinxAboutTitle": "Acerca de:", - "AboutRyujinxAboutContent": "Ryujinx es un emulador para Nintendo Switch™.\nPor favor, apóyanos en Patreon.\nEncuentra las noticias más recientes en nuestro Twitter o Discord.\nDesarrolladores interesados en contribuir pueden encontrar más información en GitHub o Discord.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Mantenido por:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Haz clic para abrir la página de contribuidores en tu navegador predeterminado.", - "AboutRyujinxSupprtersTitle": "Apoyado en Patreon Por:", "AmiiboSeriesLabel": "Serie de Amiibo", "AmiiboCharacterLabel": "Personaje", "AmiiboScanButtonLabel": "Escanear", @@ -669,14 +692,23 @@ "OpenSetupGuideMessage": "Abrir la guía de instalación", "NoUpdate": "No actualizado", "TitleUpdateVersionLabel": "Versión {0} - {1}", - "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", - "TitleBundledDlcLabel": "Bundled:", + "TitleBundledUpdateVersionLabel": "Incorporado: Versión {0}", + "TitleBundledDlcLabel": "Incorporado:", + "TitleXCIStatusPartialLabel": "Parcial", + "TitleXCIStatusTrimmableLabel": "Sin recortar", + "TitleXCIStatusUntrimmableLabel": "Recortado", + "TitleXCIStatusFailedLabel": "(Fallido)", + "TitleXCICanSaveLabel": "Ahorra {0:n0} Mb", + "TitleXCISavingLabel": "{0:n0} Mb ahorrado(s)", "RyujinxInfo": "Ryujinx - Info", "RyujinxConfirm": "Ryujinx - Confirmación", "FileDialogAllTypes": "Todos los tipos", "Never": "Nunca", "SwkbdMinCharacters": "Debe tener al menos {0} caracteres", "SwkbdMinRangeCharacters": "Debe tener {0}-{1} caracteres", + "CabinetTitle": "Diálogo Gabinete", + "CabinetDialog": "Ingresa el nuevo nombre de tu Amiibo", + "CabinetScanDialog": "Escanea tu Amiibo ahora.", "SoftwareKeyboard": "Teclado de software", "SoftwareKeyboardModeNumeric": "Debe ser sólo 0-9 o '.'", "SoftwareKeyboardModeAlphabet": "Solo deben ser caracteres no CJK", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "Añadiendo nuevos archivos...", "UpdaterExtracting": "Extrayendo actualización...", "UpdaterDownloading": "Descargando actualización...", - "Game": "Juego", "Docked": "Dock/TV", "Handheld": "Portátil", "ConnectionError": "Error de conexión.", @@ -723,18 +754,44 @@ "SelectDlcDialogTitle": "Selecciona archivo(s) de DLC", "SelectUpdateDialogTitle": "Selecciona archivo(s) de actualización", "SelectModDialogTitle": "Seleccionar un directorio de Mods", + "TrimXCIFileDialogTitle": "Verificar y recortar archivo XCI", + "TrimXCIFileDialogPrimaryText": "Esta función verificará el espacio vacío y después recortará el archivo XCI para ahorrar espacio en disco", + "TrimXCIFileDialogSecondaryText": "Tamaño de archivo actual: {0:n} MB\nTamaño de datos de juego: {1:n} MB\nAhorro de espacio en disco: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "El archivo XCI no necesita ser recortado. Verifica los logs para más detalles.", + "TrimXCIFileNoUntrimPossible": "El recorte del archivo XCI no puede ser deshecho. Verifica los registros para más detalles.", + "TrimXCIFileReadOnlyFileCannotFix": "El archivo XCI es de solo Lectura y no se le puede escribir. Lee el registro para más información.", + "TrimXCIFileFileSizeChanged": "El archivo XCI ha cambiado de tamaño desde que fue escaneado. Verifica que no se esté escribiendo al archivo y vuelve a intentarlo.", + "TrimXCIFileFreeSpaceCheckFailed": "El archivo XCI tiene datos en el área de espacio libre, no es seguro recortar.", + "TrimXCIFileInvalidXCIFile": "El archivo XCI contiene datos inválidos. Lee el registro para más información.", + "TrimXCIFileFileIOWriteError": "El archivo XCI no se puede abrir para escribirlo. Lee el registro para más información.", + "TrimXCIFileFailedPrimaryText": "El recorte del archivo XCI falló", + "TrimXCIFileCancelled": "La operación fue cancelada", + "TrimXCIFileFileUndertermined": "No se realizó ninguna operación", "UserProfileWindowTitle": "Administrar perfiles de usuario", "CheatWindowTitle": "Administrar cheats", "DlcWindowTitle": "Administrar contenido descargable", "ModWindowTitle": "Administrar Mods para {0} ({1})", "UpdateWindowTitle": "Administrar actualizaciones", - "XCITrimmerTrim": "Trim", - "XCITrimmerUntrim": "Untrim", + "XCITrimmerWindowTitle": "Recortador de archivos XCI", + "XCITrimmerTitleStatusCount": "{0} de {1} Título(s) seleccionado(s)", + "XCITrimmerTitleStatusCountWithFilter": "{0} de {1} Título(s) seleccionado(s) ({2} mostrado(s))", + "XCITrimmerTitleStatusTrimming": "Recortando {0} Título(s)...", + "XCITrimmerTitleStatusUntrimming": "Deshaciendo recorte de {0} Título(s)...", + "XCITrimmerTitleStatusFailed": "Fallido", + "XCITrimmerPotentialSavings": "Ahorro potencial", + "XCITrimmerActualSavings": "Ahorro real", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Seleccionar mostrado(s)", + "XCITrimmerDeselectDisplayed": "Deseleccionar mostrado(s)", + "XCITrimmerSortName": "Título", + "XCITrimmerSortSaved": "Ahorro de espacio", + "XCITrimmerTrim": "Recortar", + "XCITrimmerUntrim": "Deshacer recorte", "UpdateWindowUpdateAddedMessage": "{0} nueva(s) actualización(es) agregada(s)", "UpdateWindowBundledContentNotice": "Las actualizaciones agrupadas no pueden ser eliminadas, solamente deshabilitadas.", "CheatWindowHeading": "Cheats disponibles para {0} [{1}]", "BuildId": "Id de compilación:", - "DlcWindowHeading": "Contenido descargable disponible para {0} [{1}]", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "Se agregaron {0} nuevo(s) contenido(s) descargable(s)", "AutoloadDlcAddedMessage": "Se agregaron {0} nuevo(s) contenido(s) descargable(s)", "AutoloadDlcRemovedMessage": "Se eliminaron {0} contenido(s) descargable(s) faltantes", @@ -742,6 +799,7 @@ "AutoloadUpdateRemovedMessage": "Se eliminaron {0} actualización(es) faltantes", "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Editar selección", + "Continue": "Continuar", "Cancel": "Cancelar", "Save": "Guardar", "Discard": "Descartar", diff --git a/src/Ryujinx/Assets/Locales/fr_FR.json b/src/Ryujinx/Assets/Locales/fr_FR.json index 0073a2cf5..d8b524de9 100644 --- a/src/Ryujinx/Assets/Locales/fr_FR.json +++ b/src/Ryujinx/Assets/Locales/fr_FR.json @@ -1,6 +1,7 @@ { "Language": "Français", "MenuBarFileOpenApplet": "Ouvrir un programme", + "MenuBarFileOpenAppletOpenMiiApplet": "Éditeur de Mii", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Ouvrir l'éditeur Mii en mode Standalone", "SettingsTabInputDirectMouseAccess": "Accès direct à la souris", "SettingsTabSystemMemoryManagerMode": "Mode de gestion de la mémoire :", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "Installer un firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Installer un firmware depuis un fichier XCI ou ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Installer un firmware depuis un dossier", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Gérer les types de fichiers", "MenuBarToolsInstallFileTypes": "Installer les types de fichiers", "MenuBarToolsUninstallFileTypes": "Désinstaller les types de fichiers", + "MenuBarToolsXCITrimmer": "Réduire les fichiers XCI", "MenuBarView": "_Fenêtre", "MenuBarViewWindow": "Taille de la fenêtre", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Aide", "MenuBarHelpCheckForUpdates": "Vérifier les mises à jour", + "MenuBarHelpFaq": "Page de FAQ et de dépannage", + "MenuBarHelpFaqTooltip": "Ouvre la page de FAQ et de dépannage sur le wiki officiel de Ryujinx", + "MenuBarHelpSetup": "Guide d'Installation et de Configuration", + "MenuBarHelpSetupTooltip": "Ouvre le guide d'installation et de configuration sur le wiki officiel de Ryujinx", + "MenuBarHelpMultiplayer": "Guide Multijoueur (LDN/LAN)", + "MenuBarHelpMultiplayerTooltip": "Ouvre le guide de Multijoueur sur le wiki officiel de Ryujinx", "MenuBarHelpAbout": "À propos", "MenuSearch": "Rechercher...", "GameListHeaderFavorite": "Favoris", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "Ouvre le dossier contenant les mods du jeu", "GameListContextMenuOpenSdModsDirectory": "Ouvrir le dossier des mods Atmosphère", "GameListContextMenuOpenSdModsDirectoryToolTip": "Ouvre le dossier alternatif de la carte SD Atmosphère qui contient les mods de l'application. Utile pour les mods conçus pour console.", + "GameListContextMenuTrimXCI": "Vérifier et réduire les fichiers XCI", + "GameListContextMenuTrimXCIToolTip": "Vérifier et réduire les fichiers XCI pour économiser de l'espace", "StatusBarGamesLoaded": "{0}/{1} Jeux chargés", "StatusBarSystemVersion": "Version du Firmware: {0}", + "StatusBarXCIFileTrimming": "Réduction du fichier XCI '{0}'", "LinuxVmMaxMapCountDialogTitle": "Limite basse pour les mappings mémoire détectée", "LinuxVmMaxMapCountDialogTextPrimary": "Voulez-vous augmenter la valeur de vm.max_map_count à {0}", "LinuxVmMaxMapCountDialogTextSecondary": "Certains jeux peuvent essayer de créer plus de mappings mémoire que ce qui est actuellement autorisé. Ryujinx plantera dès que cette limite sera dépassée.", @@ -400,6 +414,8 @@ "InputDialogTitle": "Fenêtre d'entrée de texte", "InputDialogOk": "OK", "InputDialogCancel": "Annuler", + "InputDialogCancelling": "Annulation en cours", + "InputDialogClose": "Fermer", "InputDialogAddNewProfileTitle": "Choisir un nom de profil", "InputDialogAddNewProfileHeader": "Merci d'entrer un nom de profil", "InputDialogAddNewProfileSubtext": "(Longueur max.: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Extraction de la mise à jour…", "DialogUpdaterRenamingMessage": "Renommage de la mise à jour...", "DialogUpdaterAddingFilesMessage": "Ajout d'une nouvelle mise à jour...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Mise à jour terminée !", "DialogUpdaterRestartMessage": "Voulez-vous redémarrer Ryujinx maintenant ?", "DialogUpdaterNoInternetMessage": "Vous n'êtes pas connecté à Internet !", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "Types de fichiers désinstallés avec succès!", "DialogUninstallFileTypesErrorMessage": "Échec de la désinstallation des types de fichiers.", "DialogOpenSettingsWindowLabel": "Ouvrir la fenêtre de configuration", + "DialogOpenXCITrimmerWindowLabel": "Fenêtre de réduction de fichiers XCI", "DialogControllerAppletTitle": "Programme Manette", "DialogMessageDialogErrorExceptionMessage": "Erreur lors de l'affichage de la boîte de dialogue : {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Erreur lors de l'affichage du clavier logiciel: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVoulez-vous continuer ?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installation du firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Version du système {0} installée avec succès.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Il n'y aurait aucun autre profil à ouvrir si le profil sélectionné est supprimé", "DialogUserProfileDeletionConfirmMessage": "Voulez-vous supprimer le profil sélectionné ?", "DialogUserProfileUnsavedChangesTitle": "Avertissement - Modifications non enregistrées", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "Cliquez pour ouvrir le site de Ryujinx dans votre navigateur par défaut.", "AboutDisclaimerMessage": "Ryujinx n'est pas affilié à Nintendo™,\nou à aucun de ses partenaires, de quelque manière que ce soit.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) est utilisé\ndans notre émulation Amiibo.", - "AboutPatreonUrlTooltipMessage": "Cliquez pour ouvrir la page Patreon de Ryujinx dans votre navigateur par défaut.", "AboutGithubUrlTooltipMessage": "Cliquez pour ouvrir la page GitHub de Ryujinx dans votre navigateur par défaut.", "AboutDiscordUrlTooltipMessage": "Cliquez pour ouvrir une invitation au serveur Discord de Ryujinx dans votre navigateur par défaut.", - "AboutTwitterUrlTooltipMessage": "Cliquez pour ouvrir la page Twitter de Ryujinx dans votre navigateur par défaut.", "AboutRyujinxAboutTitle": "À propos :", - "AboutRyujinxAboutContent": "Ryujinx est un émulateur pour la Nintendo Switch™.\nMerci de nous soutenir sur Patreon.\nObtenez toutes les dernières actualités sur notre Twitter ou notre Discord.\nLes développeurs intéressés à contribuer peuvent en savoir plus sur notre GitHub ou notre Discord.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Maintenu par :", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Cliquez pour ouvrir la page Contributeurs dans votre navigateur par défaut.", - "AboutRyujinxSupprtersTitle": "Supporté sur Patreon par :", "AmiiboSeriesLabel": "Séries Amiibo", "AmiiboCharacterLabel": "Personnage", "AmiiboScanButtonLabel": "Scanner", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "Version {0}", "TitleBundledUpdateVersionLabel": "Inclus avec le jeu: Version {0}", "TitleBundledDlcLabel": "Inclus avec le jeu :", + "TitleXCIStatusPartialLabel": "Partiel", + "TitleXCIStatusTrimmableLabel": "Non réduit", + "TitleXCIStatusUntrimmableLabel": "Réduit", + "TitleXCIStatusFailedLabel": "(Échoué)", + "TitleXCICanSaveLabel": "Sauvegarde de {0:n0} Mo", + "TitleXCISavingLabel": "Sauvegardé {0:n0} Mo", "RyujinxInfo": "Ryujinx - Info", "RyujinxConfirm": "Ryujinx - Confirmation", "FileDialogAllTypes": "Tous les types", "Never": "Jamais", "SwkbdMinCharacters": "Doit comporter au moins {0} caractères", "SwkbdMinRangeCharacters": "Doit comporter entre {0} et {1} caractères", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Clavier logiciel", "SoftwareKeyboardModeNumeric": "Doit être 0-9 ou '.' uniquement", "SoftwareKeyboardModeAlphabet": "Doit être uniquement des caractères non CJK", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "Ajout des nouveaux fichiers...", "UpdaterExtracting": "Extraction de la mise à jour…", "UpdaterDownloading": "Téléchargement de la mise à jour...", - "Game": "Jeu", "Docked": "Mode station d'accueil", "Handheld": "Mode Portable", "ConnectionError": "Erreur de connexion.", @@ -723,17 +754,45 @@ "SelectDlcDialogTitle": "Sélectionner les fichiers DLC", "SelectUpdateDialogTitle": "Sélectionner les fichiers de mise à jour", "SelectModDialogTitle": "Sélectionner le répertoire du mod", + "TrimXCIFileDialogTitle": "Vérifier et Réduire le fichier XCI", + "TrimXCIFileDialogPrimaryText": "Cette fonction va vérifier l'espace vide, puis réduire le fichier XCI pour économiser de l'espace de disque dur.", + "TrimXCIFileDialogSecondaryText": "Taille actuelle du fichier: {0:n} MB\nTaille des données de jeux: {1:n} MB\nÉconomie d'espaces sur le disque: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "Fichier XCI n'a pas besoin d'être réduit. Regarder les journaux pour plus de détails", + "TrimXCIFileNoUntrimPossible": "Fichier XCI ne peut pas être dé-réduit. Regarder les journaux pour plus de détails", + "TrimXCIFileReadOnlyFileCannotFix": "Fichier XCI est en Lecture Seule et n'a pas pu être rendu accessible en écriture. Regarder les journaux pour plus de détails", + "TrimXCIFileFileSizeChanged": "Fichier XCI a changé en taille depuis qu'il a été scanné. Vérifier que le fichier n'est pas en cours d'écriture et réessayer.", + "TrimXCIFileFreeSpaceCheckFailed": "Fichier XCI a des données dans la zone d'espace libre, ce n'est pas sûr de réduire", + "TrimXCIFileInvalidXCIFile": "Fichier XCI contient des données invalides. Regarder les journaux pour plus de détails", + "TrimXCIFileFileIOWriteError": "Fichier XCI n'a pas pu été ouvert pour écriture. Regarder les journaux pour plus de détails", + "TrimXCIFileFailedPrimaryText": "Réduction du fichier XCI a échoué", + "TrimXCIFileCancelled": "L'opération a été annulée", + "TrimXCIFileFileUndertermined": "Aucune opération a été faite", "UserProfileWindowTitle": "Gestionnaire de profils utilisateur", "CheatWindowTitle": "Gestionnaire de cheats", "DlcWindowTitle": "Gérer le contenu téléchargeable pour {0} ({1})", "ModWindowTitle": "Gérer les mods pour {0} ({1})", "UpdateWindowTitle": "Gestionnaire de mises à jour", + "XCITrimmerWindowTitle": "Rogneur de fichier XCI", + "XCITrimmerTitleStatusCount": "{0} sur {1} Fichier(s) Sélectionnés", + "XCITrimmerTitleStatusCountWithFilter": "{0} sur {1} Fichier(s) Sélectionnés ({2} affiché(s)", + "XCITrimmerTitleStatusTrimming": "Réduction de {0} Fichier(s)...", + "XCITrimmerTitleStatusUntrimming": "Dé-Réduction de {0} Fichier(s)...", + "XCITrimmerTitleStatusFailed": "Échoué", + "XCITrimmerPotentialSavings": "Économies potentielles d'espace de disque dur", + "XCITrimmerActualSavings": "Économies actualles d'espace de disque dur", + "XCITrimmerSavingsMb": "{0:n0} Mo", + "XCITrimmerSelectDisplayed": "Sélectionner Affiché", + "XCITrimmerDeselectDisplayed": "Désélectionner Affiché", + "XCITrimmerSortName": "Titre", + "XCITrimmerSortSaved": "Économies de disque dur", + "XCITrimmerTrim": "Réduire", + "XCITrimmerUntrim": "Dé-Réduire", "UpdateWindowUpdateAddedMessage": "{0} nouvelle(s) mise(s) à jour ajoutée(s)", "UpdateWindowBundledContentNotice": "Les mises à jour incluses avec le jeu ne peuvent pas être supprimées mais peuvent être désactivées.", "CheatWindowHeading": "Cheats disponibles pour {0} [{1}]", "BuildId": "BuildId :", "DlcWindowBundledContentNotice": "Les DLC inclus avec le jeu ne peuvent pas être supprimés mais peuvent être désactivés.", - "DlcWindowHeading": "{0} Contenu(s) téléchargeable(s)", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} nouveau(x) contenu(s) téléchargeable(s) ajouté(s)", "AutoloadDlcAddedMessage": "{0} nouveau(x) contenu(s) téléchargeable(s) ajouté(s)", "AutoloadDlcRemovedMessage": "{0} contenu(s) téléchargeable(s) manquant(s) supprimé(s)", @@ -741,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} mises à jour manquantes supprimées", "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Éditer la sélection", + "Continue": "Continuer", "Cancel": "Annuler", "Save": "Enregistrer", "Discard": "Abandonner", @@ -808,5 +868,17 @@ "MultiplayerMode": "Mode :", "MultiplayerModeTooltip": "Changer le mode multijoueur LDN.\n\nLdnMitm modifiera la fonctionnalité de jeu sans fil local/jeu local dans les jeux pour fonctionner comme s'il s'agissait d'un LAN, permettant des connexions locales sur le même réseau avec d'autres instances de Ryujinx et des consoles Nintendo Switch piratées ayant le module ldn_mitm installé.\n\nLe multijoueur nécessite que tous les joueurs soient sur la même version du jeu (par exemple, Super Smash Bros. Ultimate v13.0.1 ne peut pas se connecter à v13.0.0).\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.", "MultiplayerModeDisabled": "Désactivé", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Désactiver PàP Hébergement de Réseau (pourrait augmenter la latence)", + "MultiplayerDisableP2PTooltip": "Désactiver PàP hébergement de réseau, les postes vont proxy avec le serveur principal au lieu de se connecter directement à vous.", + "LdnPassphrase": "Mot de passe Réseau :", + "LdnPassphraseTooltip": "Vous pourez seulement voir les jeux hébergé avec le même mot de passe que vous.", + "LdnPassphraseInputTooltip": "Entrer un mot de passe dans le format Ryujinx-<8 hex chars>. Vous pourez seulement voir les jeux hébergé avec le même mot de passe que vous.", + "LdnPassphraseInputPublic": "(publique)", + "GenLdnPass": "Générer Aléatoire", + "GenLdnPassTooltip": "Génére un nouveau mot de passe, qui peut être partagé avec les autres.", + "ClearLdnPass": "Supprimer", + "ClearLdnPassTooltip": "Supprime le mot de passe actuel, ce qui vous remet sur le réseau public.", + "InvalidLdnPassphrase": "Mot de passe invalide! Il doit être dans le format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/he_IL.json b/src/Ryujinx/Assets/Locales/he_IL.json index 91e3e24e4..b45ba67a3 100644 --- a/src/Ryujinx/Assets/Locales/he_IL.json +++ b/src/Ryujinx/Assets/Locales/he_IL.json @@ -1,6 +1,7 @@ { "Language": "עִברִית", "MenuBarFileOpenApplet": "פתח יישומון", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "פתח את יישומון עורך ה- Mii במצב עצמאי", "SettingsTabInputDirectMouseAccess": "גישה ישירה לעכבר", "SettingsTabSystemMemoryManagerMode": "מצב מנהל זיכרון:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "התקן קושחה", "MenuBarFileToolsInstallFirmwareFromFile": "התקן קושחה מקובץ- ZIP/XCI", "MenuBarFileToolsInstallFirmwareFromDirectory": "התקן קושחה מתוך תקייה", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "ניהול סוגי קבצים", "MenuBarToolsInstallFileTypes": "סוגי קבצי התקנה", "MenuBarToolsUninstallFileTypes": "סוגי קבצי הסרה", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_View", "MenuBarViewWindow": "Window Size", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_עזרה", "MenuBarHelpCheckForUpdates": "חפש עדכונים", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "אודות", "MenuSearch": "חפש...", "GameListHeaderFavorite": "אהוב", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "פותח את התיקייה שמכילה מודים של האפליקציה", "GameListContextMenuOpenSdModsDirectory": "פתח תיקיית מודים של Atmosphere", "GameListContextMenuOpenSdModsDirectoryToolTip": "פותח את תיקיית כרטיס ה-SD החלופית של Atmosphere המכילה את המודים של האפליקציה. שימושי עבור מודים שארוזים עבור חומרה אמיתית.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{1}/{0} משחקים נטענו", "StatusBarSystemVersion": "גרסת מערכת: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "זוהתה מגבלה נמוכה עבור מיפויי זיכרון", "LinuxVmMaxMapCountDialogTextPrimary": "האם תרצה להגביר את הערך של vm.max_map_count ל{0}", "LinuxVmMaxMapCountDialogTextSecondary": "משחקים מסוימים עלולים לייצר עוד מיפויי זיכרון ממה שמתאפשר. Ryujinx יקרוס ברגע שהמגבלה תחרוג.", @@ -400,6 +414,8 @@ "InputDialogTitle": "דיאלוג קלט", "InputDialogOk": "בסדר", "InputDialogCancel": "ביטול", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "בחרו את שם הפרופיל", "InputDialogAddNewProfileHeader": "אנא הזינו שם לפרופיל", "InputDialogAddNewProfileSubtext": "(אורך מרבי: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "מחלץ עדכון...", "DialogUpdaterRenamingMessage": "משנה את שם העדכון...", "DialogUpdaterAddingFilesMessage": "מוסיף עדכון חדש...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "העדכון הושלם!", "DialogUpdaterRestartMessage": "האם אתם רוצים להפעיל מחדש את ריוג'ינקס עכשיו?", "DialogUpdaterNoInternetMessage": "אתם לא מחוברים לאינטרנט!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "סוגי קבצים הוסרו בהצלחה!", "DialogUninstallFileTypesErrorMessage": "נכשל בהסרת סוגי קבצים.", "DialogOpenSettingsWindowLabel": "פתח את חלון ההגדרות", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "יישומון בקר", "DialogMessageDialogErrorExceptionMessage": "שגיאה בהצגת דיאלוג ההודעה: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "שגיאה בהצגת תוכנת המקלדת: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nהאם ברצונך להמשיך?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "מתקין קושחה...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "גרסת המערכת {0} הותקנה בהצלחה.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "לא יהיו פרופילים אחרים שייפתחו אם הפרופיל שנבחר יימחק", "DialogUserProfileDeletionConfirmMessage": "האם ברצונך למחוק את הפרופיל שנבחר", "DialogUserProfileUnsavedChangesTitle": "אזהרה - שינויים לא שמורים", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "לחץ כדי לפתוח את אתר ריוג'ינקס בדפדפן ברירת המחדל שלך.", "AboutDisclaimerMessage": "ריוג'ינקס אינה מזוהת עם נינטנדו,\nאו שוטפייה בכל דרך שהיא.", "AboutAmiiboDisclaimerMessage": "ממשק אמיבו (www.amiiboapi.com) משומש בהדמיית האמיבו שלנו.", - "AboutPatreonUrlTooltipMessage": "לחץ כדי לפתוח את דף הפטראון של ריוג'ינקס בדפדפן ברירת המחדל שלך.", "AboutGithubUrlTooltipMessage": "לחץ כדי לפתוח את דף הגיטהב של ריוג'ינקס בדפדפן ברירת המחדל שלך.", "AboutDiscordUrlTooltipMessage": "לחץ כדי לפתוח הזמנה לשרת הדיסקורד של ריוג'ינקס בדפדפן ברירת המחדל שלך.", - "AboutTwitterUrlTooltipMessage": "לחץ כדי לפתוח את דף הטוויטר של Ryujinx בדפדפן ברירת המחדל שלך.", "AboutRyujinxAboutTitle": "אודות:", - "AboutRyujinxAboutContent": "ריוג'ינקס הוא אמולטור עבור הנינטנדו סוויץ' (כל הזכויות שמורות).\nבבקשה תתמכו בנו בפטראון.\nקבל את כל החדשות האחרונות בטוויטר או בדיסקורד שלנו.\nמפתחים המעוניינים לתרום יכולים לקבל מידע נוסף ב-גיטהאב או ב-דיסקורד שלנו.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "מתוחזק על ידי:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "לחץ כדי לפתוח את דף התורמים בדפדפן ברירת המחדל שלך.", - "AboutRyujinxSupprtersTitle": "תמוך באמצעות Patreon", "AmiiboSeriesLabel": "סדרת אמיבו", "AmiiboCharacterLabel": "דמות", "AmiiboScanButtonLabel": "סרוק את זה", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "גרסה {0}", "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "ריוג'ינקס - מידע", "RyujinxConfirm": "ריוג'ינקס - אישור", "FileDialogAllTypes": "כל הסוגים", "Never": "אף פעם", "SwkbdMinCharacters": "לפחות {0} תווים", "SwkbdMinRangeCharacters": "באורך {0}-{1} תווים", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "מקלדת וירטואלית", "SoftwareKeyboardModeNumeric": "חייב להיות בין 0-9 או '.' בלבד", "SoftwareKeyboardModeAlphabet": "מחויב להיות ללא אותיות CJK", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "מוסיף קבצים חדשים...", "UpdaterExtracting": "מחלץ עדכון...", "UpdaterDownloading": "מוריד עדכון...", - "Game": "משחק", "Docked": "בתחנת עגינה", "Handheld": "נייד", "ConnectionError": "שגיאת חיבור", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "בחרו קבצי הרחבות משחק", "SelectUpdateDialogTitle": "בחרו קבצי עדכון", "SelectModDialogTitle": "בחר תיקיית מודים", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "ניהול פרופילי משתמש", "CheatWindowTitle": "נהל צ'יטים למשחק", "DlcWindowTitle": "נהל הרחבות משחק עבור {0} ({1})", "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "נהל עדכוני משחקים", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "{0} מוד(ים)", "UserProfilesEditProfile": "ערוך נבחר/ים", + "Continue": "Continue", "Cancel": "בטל", "Save": "שמור", "Discard": "השלך", @@ -810,5 +868,17 @@ "MultiplayerMode": "מצב:", "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", "MultiplayerModeDisabled": "Disabled", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/it_IT.json b/src/Ryujinx/Assets/Locales/it_IT.json index 2a92e70dc..4a42cb6aa 100644 --- a/src/Ryujinx/Assets/Locales/it_IT.json +++ b/src/Ryujinx/Assets/Locales/it_IT.json @@ -1,6 +1,7 @@ { "Language": "Italiano", "MenuBarFileOpenApplet": "Apri applet", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Apri l'applet Mii Editor in modalità Standalone", "SettingsTabInputDirectMouseAccess": "Accesso diretto al mouse", "SettingsTabSystemMemoryManagerMode": "Modalità di gestione della memoria:", @@ -27,6 +28,9 @@ "MenuBarToolsInstallFirmware": "Installa firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Installa un firmware da file XCI o ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Installa un firmare da una cartella", + "MenuBarToolsInstallKeys": "Installa Chiavi", + "MenuBarFileToolsInstallKeysFromFile": "Installa Chiavi da file KEYS o ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Installa Chiavi da una Cartella", "MenuBarToolsManageFileTypes": "Gestisci i tipi di file", "MenuBarToolsInstallFileTypes": "Installa i tipi di file", "MenuBarToolsUninstallFileTypes": "Disinstalla i tipi di file", @@ -40,6 +44,12 @@ "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Aiuto", "MenuBarHelpCheckForUpdates": "Controlla aggiornamenti", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "Informazioni", "MenuSearch": "Cerca...", "GameListHeaderFavorite": "Preferito", @@ -457,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Estrazione dell'aggiornamento...", "DialogUpdaterRenamingMessage": "Rinominazione dell'aggiornamento...", "DialogUpdaterAddingFilesMessage": "Aggiunta del nuovo aggiornamento...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Aggiornamento completato!", "DialogUpdaterRestartMessage": "Vuoi riavviare Ryujinx adesso?", "DialogUpdaterNoInternetMessage": "Non sei connesso ad Internet!", @@ -504,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVuoi continuare?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installazione del firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "La versione del sistema {0} è stata installata.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "E' stato trovato un file di chiavi invalido ' {0}", + "DialogKeysInstallerKeysInstallTitle": "Installa Chavi", + "DialogKeysInstallerKeysInstallMessage": "Un nuovo file di Chiavi sarà intallato.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nQuesto potrebbe sovrascrivere alcune delle Chiavi già installate.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nVuoi continuare?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installando le chiavi...", + "DialogKeysInstallerKeysInstallSuccessMessage": "Nuovo file di chiavi installato con successo.", "DialogUserProfileDeletionWarningMessage": "Non ci sarebbero altri profili da aprire se il profilo selezionato viene cancellato", "DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?", "DialogUserProfileUnsavedChangesTitle": "Attenzione - Modifiche Non Salvate", @@ -540,15 +558,13 @@ "AboutUrlTooltipMessage": "Clicca per aprire il sito web di Ryujinx nel tuo browser predefinito.", "AboutDisclaimerMessage": "Ryujinx non è affiliato con Nintendo™,\no i suoi partner, in alcun modo.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) è usata\nnella nostra emulazione Amiibo.", - "AboutPatreonUrlTooltipMessage": "Clicca per aprire la pagina Patreon di Ryujinx nel tuo browser predefinito.", "AboutGithubUrlTooltipMessage": "Clicca per aprire la pagina GitHub di Ryujinx nel tuo browser predefinito.", "AboutDiscordUrlTooltipMessage": "Clicca per aprire un invito al server Discord di Ryujinx nel tuo browser predefinito.", - "AboutTwitterUrlTooltipMessage": "Clicca per aprire la pagina Twitter di Ryujinx nel tuo browser predefinito.", "AboutRyujinxAboutTitle": "Informazioni:", - "AboutRyujinxAboutContent": "Ryujinx è un emulatore per la console Nintendo Switch™.\nSostienici su Patreon.\nRicevi tutte le ultime notizie sul nostro Twitter o su Discord.\nGli sviluppatori interessati a contribuire possono trovare più informazioni sul nostro GitHub o Discord.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Mantenuto da:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Clicca per aprire la pagina dei contributori nel tuo browser predefinito.", - "AboutRyujinxSupprtersTitle": "Supportato su Patreon da:", "AmiiboSeriesLabel": "Serie Amiibo", "AmiiboCharacterLabel": "Personaggio", "AmiiboScanButtonLabel": "Scansiona", @@ -690,6 +706,9 @@ "Never": "Mai", "SwkbdMinCharacters": "Non può avere meno di {0} caratteri", "SwkbdMinRangeCharacters": "Può avere da {0} a {1} caratteri", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Tastiera software", "SoftwareKeyboardModeNumeric": "Deve essere solo 0-9 o '.'", "SoftwareKeyboardModeAlphabet": "Deve essere solo caratteri non CJK", @@ -703,7 +722,6 @@ "UpdaterAddingFiles": "Aggiunta dei nuovi file...", "UpdaterExtracting": "Estrazione dell'aggiornamento...", "UpdaterDownloading": "Download dell'aggiornamento...", - "Game": "Gioco", "Docked": "TV", "Handheld": "Portatile", "ConnectionError": "Errore di connessione.", @@ -774,7 +792,7 @@ "CheatWindowHeading": "Trucchi disponibili per {0} [{1}]", "BuildId": "ID Build", "DlcWindowBundledContentNotice": "i DLC \"impacchettati\" non possono essere rimossi, ma solo disabilitati.", - "DlcWindowHeading": "DLC disponibili per {0} [{1}]", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} nuovo/i contenuto/i scaricabile/i aggiunto/i", "AutoloadDlcAddedMessage": "{0} contenuto/i scaricabile/i aggiunto/i", "AutoloadDlcRemovedMessage": "{0} contenuto/i scaricabile/i mancante/i rimosso/i", @@ -850,5 +868,17 @@ "MultiplayerMode": "Modalità:", "MultiplayerModeTooltip": "Cambia la modalità multigiocatore LDN.\n\nLdnMitm modificherà la funzionalità locale wireless/local play nei giochi per funzionare come se fosse in modalità LAN, consentendo connessioni locali sulla stessa rete con altre istanze di Ryujinx e console Nintendo Switch modificate che hanno il modulo ldn_mitm installato.\n\nLa modalità multigiocatore richiede che tutti i giocatori usino la stessa versione del gioco (es. Super Smash Bros. Ultimate v13.0.1 non può connettersi con la v13.0.0).\n\nNel dubbio, lascia l'opzione su Disabilitato.", "MultiplayerModeDisabled": "Disabilitato", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/ja_JP.json b/src/Ryujinx/Assets/Locales/ja_JP.json index b8e5870a6..c18ac066b 100644 --- a/src/Ryujinx/Assets/Locales/ja_JP.json +++ b/src/Ryujinx/Assets/Locales/ja_JP.json @@ -1,6 +1,7 @@ { "Language": "日本語", "MenuBarFileOpenApplet": "アプレットを開く", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "スタンドアロンモードで Mii エディタアプレットを開きます", "SettingsTabInputDirectMouseAccess": "マウス直接アクセス", "SettingsTabSystemMemoryManagerMode": "メモリ管理モード:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "ファームウェアをインストール", "MenuBarFileToolsInstallFirmwareFromFile": "XCI または ZIP からファームウェアをインストール", "MenuBarFileToolsInstallFirmwareFromDirectory": "ディレクトリからファームウェアをインストール", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "ファイル形式を管理", "MenuBarToolsInstallFileTypes": "ファイル形式をインストール", "MenuBarToolsUninstallFileTypes": "ファイル形式をアンインストール", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_View", "MenuBarViewWindow": "Window Size", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "ヘルプ(_H)", "MenuBarHelpCheckForUpdates": "アップデートを確認", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "Ryujinx について", "MenuSearch": "検索...", "GameListHeaderFavorite": "お気に入り", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "アプリケーションの Mod データを格納するディレクトリを開きます", "GameListContextMenuOpenSdModsDirectory": "Atmosphere Mods ディレクトリを開く", "GameListContextMenuOpenSdModsDirectoryToolTip": "アプリケーションの Mod データを格納する SD カードの Atmosphere ディレクトリを開きます. 実際のハードウェア用に作成された Mod データに有用です.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} ゲーム", "StatusBarSystemVersion": "システムバージョン: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "メモリマッピング上限値が小さすぎます", "LinuxVmMaxMapCountDialogTextPrimary": "vm.max_map_count の値を {0}に増やしますか?", "LinuxVmMaxMapCountDialogTextSecondary": "ゲームによっては, 現在許可されているサイズより大きなメモリマッピングを作成しようとすることがあります. この制限を超えると, Ryjinx はすぐにクラッシュします.", @@ -400,6 +414,8 @@ "InputDialogTitle": "入力ダイアログ", "InputDialogOk": "OK", "InputDialogCancel": "キャンセル", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "プロファイル名を選択", "InputDialogAddNewProfileHeader": "プロファイル名を入力してください", "InputDialogAddNewProfileSubtext": "(最大長: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "アップデートを展開中...", "DialogUpdaterRenamingMessage": "アップデートをリネーム中...", "DialogUpdaterAddingFilesMessage": "新規アップデートを追加中...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "アップデート完了!", "DialogUpdaterRestartMessage": "すぐに Ryujinx を再起動しますか?", "DialogUpdaterNoInternetMessage": "インターネットに接続されていません!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "ファイル形式のアンインストールに成功しました!", "DialogUninstallFileTypesErrorMessage": "ファイル形式のアンインストールに失敗しました.", "DialogOpenSettingsWindowLabel": "設定ウインドウを開く", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "コントローラアプレット", "DialogMessageDialogErrorExceptionMessage": "メッセージダイアログ表示エラー: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "ソフトウェアキーボード表示エラー: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n続けてよろしいですか?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "ファームウェアをインストール中...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "システムバージョン {0} が正常にインストールされました.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "選択されたプロファイルを削除すると,プロファイルがひとつも存在しなくなります", "DialogUserProfileDeletionConfirmMessage": "選択されたプロファイルを削除しますか", "DialogUserProfileUnsavedChangesTitle": "警告 - 保存されていない変更", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx のウェブサイトを開きます.", "AboutDisclaimerMessage": "Ryujinx は Nintendo™ および\nそのパートナー企業とは一切関係ありません.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) は\nAmiibo エミュレーションに使用されています.", - "AboutPatreonUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Patreon ページを開きます.", "AboutGithubUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Github ページを開きます.", "AboutDiscordUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Discord サーバを開きます.", - "AboutTwitterUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Twitter ページを開きます.", "AboutRyujinxAboutTitle": "Ryujinx について:", - "AboutRyujinxAboutContent": "Ryujinx は Nintendo Switch™ のエミュレータです.\nPatreon で私達の活動を支援してください.\n最新の情報は Twitter または Discord から取得できます.\n貢献したい開発者の方は GitHub または Discord で詳細をご確認ください.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "開発者:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "クリックするとデフォルトのブラウザで 貢献者のページを開きます.", - "AboutRyujinxSupprtersTitle": "Patreon での支援者:", "AmiiboSeriesLabel": "Amiibo シリーズ", "AmiiboCharacterLabel": "キャラクタ", "AmiiboScanButtonLabel": "スキャン", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "バージョン {0} - {1}", "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - 情報", "RyujinxConfirm": "Ryujinx - 確認", "FileDialogAllTypes": "すべての種別", "Never": "決して", "SwkbdMinCharacters": "最低 {0} 文字必要です", "SwkbdMinRangeCharacters": "{0}-{1} 文字にしてください", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "ソフトウェアキーボード", "SoftwareKeyboardModeNumeric": "0-9 または '.' のみでなければなりません", "SoftwareKeyboardModeAlphabet": "CJK文字以外のみ", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "新規ファイルを追加中...", "UpdaterExtracting": "アップデートを展開中...", "UpdaterDownloading": "アップデートをダウンロード中...", - "Game": "ゲーム", "Docked": "ドッキング", "Handheld": "携帯", "ConnectionError": "接続エラー.", @@ -723,18 +754,44 @@ "SelectDlcDialogTitle": "DLC ファイルを選択", "SelectUpdateDialogTitle": "アップデートファイルを選択", "SelectModDialogTitle": "modディレクトリを選択", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "ユーザプロファイルを管理", "CheatWindowTitle": "チート管理", "DlcWindowTitle": "DLC 管理", "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "アップデート管理", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", "UpdateWindowBundledContentNotice": "Bundled updates cannot be removed, only disabled.", "CheatWindowHeading": "利用可能なチート {0} [{1}]", "BuildId": "ビルドID:", - "DlcWindowHeading": "利用可能な DLC {0} [{1}]", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", @@ -742,6 +799,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "編集", + "Continue": "Continue", "Cancel": "キャンセル", "Save": "セーブ", "Discard": "破棄", @@ -809,5 +867,17 @@ "MultiplayerMode": "モード:", "MultiplayerModeTooltip": "LDNマルチプレイヤーモードを変更します.\n\nldn_mitmモジュールがインストールされた, 他のRyujinxインスタンスや,ハックされたNintendo Switchコンソールとのローカル/同一ネットワーク接続を可能にします.\n\nマルチプレイでは, すべてのプレイヤーが同じゲームバージョンである必要があります(例:Super Smash Bros. Ultimate v13.0.1はv13.0.0に接続できません).\n\n不明な場合は「無効」のままにしてください.", "MultiplayerModeDisabled": "無効", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/ko_KR.json b/src/Ryujinx/Assets/Locales/ko_KR.json index 5bda1565b..ad44b5b14 100644 --- a/src/Ryujinx/Assets/Locales/ko_KR.json +++ b/src/Ryujinx/Assets/Locales/ko_KR.json @@ -1,6 +1,7 @@ { "Language": "한국어", "MenuBarFileOpenApplet": "애플릿 열기", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii 편집 애플릿", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "독립 실행형 모드로 Mii 편집기 애플릿 열기", "SettingsTabInputDirectMouseAccess": "마우스 직접 접근", "SettingsTabSystemMemoryManagerMode": "메모리 관리자 모드 :", @@ -30,6 +31,9 @@ "MenuBarToolsInstallFirmware": "펌웨어 설치", "MenuBarFileToolsInstallFirmwareFromFile": "XCI 또는 ZIP으로 펌웨어 설치", "MenuBarFileToolsInstallFirmwareFromDirectory": "디렉터리에서 펌웨어 설치", + "MenuBarToolsInstallKeys": "설치 키", + "MenuBarFileToolsInstallKeysFromFile": "키나 ZIP에서 키 설치", + "MenuBarFileToolsInstallKeysFromFolder": "디렉터리에서 키 설치", "MenuBarToolsManageFileTypes": "파일 형식 관리", "MenuBarToolsInstallFileTypes": "파일 형식 설치", "MenuBarToolsUninstallFileTypes": "파일 형식 제거", @@ -40,6 +44,12 @@ "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "도움말(_H)", "MenuBarHelpCheckForUpdates": "업데이트 확인", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "정보", "MenuSearch": "찾기...", "GameListHeaderFavorite": "즐겨찾기", @@ -457,6 +467,7 @@ "DialogUpdaterExtractionMessage": "업데이트 추출 중...", "DialogUpdaterRenamingMessage": "이름 변경 업데이트...", "DialogUpdaterAddingFilesMessage": "새 업데이트 추가 중...", + "DialogUpdaterShowChangelogMessage": "변경 로그 보기", "DialogUpdaterCompleteMessage": "업데이트가 완료되었습니다!", "DialogUpdaterRestartMessage": "지금 Ryujinx를 다시 시작하시겠습니까?", "DialogUpdaterNoInternetMessage": "인터넷에 연결되어 있지 않습니다!", @@ -479,7 +490,7 @@ "DialogControllerAppletTitle": "컨트롤러 애플릿", "DialogMessageDialogErrorExceptionMessage": "메시지 대화 상자 표시 오류 : {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "소프트웨어 키보드 표시 오류 : {0}", - "DialogErrorAppletErrorExceptionMessage": "ErrorApplet 대화 상자 표시 오류 : {0}", + "DialogErrorAppletErrorExceptionMessage": "애플릿 오류류 대화 상자 표시 오류 : {0}", "DialogUserErrorDialogMessage": "{0}: {1}", "DialogUserErrorDialogInfoMessage": "\n이 오류를 해결하는 방법에 대한 자세한 내용은 설정 가이드를 참조하세요.", "DialogUserErrorDialogTitle": "Ryujinx 오류 ({0})", @@ -504,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n계속하시겠습니까?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "펌웨어 설치 중...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "시스템 버전 {0}이(가) 설치되었습니다.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "{0}에서 잘못된 키 파일이 발견", + "DialogKeysInstallerKeysInstallTitle": "설치 키", + "DialogKeysInstallerKeysInstallMessage": "새로운 키 파일이 설치됩니다.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\n이로 인해 현재 설치된 키 중 일부가 대체될 수 있습니다.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\n계속하시겠습니까?", + "DialogKeysInstallerKeysInstallWaitMessage": "키 설치 중...", + "DialogKeysInstallerKeysInstallSuccessMessage": "새로운 키 파일이 성공적으로 설치되었습니다.", "DialogUserProfileDeletionWarningMessage": "선택한 프로필을 삭제하면 다른 프로필을 열 수 없음", "DialogUserProfileDeletionConfirmMessage": "선택한 프로필을 삭제하시겠습니까?", "DialogUserProfileUnsavedChangesTitle": "경고 - 저장되지 않은 변경 사항", @@ -540,15 +558,13 @@ "AboutUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx 웹사이트가 열립니다.", "AboutDisclaimerMessage": "Ryujinx는 Nintendo™\n또는 그 파트너와 제휴한 바가 없습니다.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI(www.amiiboapi.com)는\nAmiibo 에뮬레이션에 사용됩니다.", - "AboutPatreonUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx Patreon 페이지가 열립니다.", "AboutGithubUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx GitHub 페이지가 열립니다.", "AboutDiscordUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx 디스코드 서버 초대장이 열립니다.", - "AboutTwitterUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx 트위터 페이지가 열립니다.", "AboutRyujinxAboutTitle": "정보 :", - "AboutRyujinxAboutContent": "Ryujinx는 Nintendo Switch™용 에뮬레이터입니다.\nPatreon에서 저희를 후원해 주세요.\nTwitter나 Discord에서 최신 뉴스를 모두 받아보세요.\n기여에 관심이 있는 개발자는 GitHub이나 Discord에서 자세한 내용을 알아볼 수 있습니다.", + "AboutRyujinxAboutContent": "Ryujinx는 Nintendo Switch™용 에뮬레이터입니다.\n모든 최신 소식을 Discord에서 확인하세요.\n기여에 관심이 있는 개발자는 GitHub 또는 Discord에서 자세한 내용을 확인할 수 있습니다.", "AboutRyujinxMaintainersTitle": "유지 관리 :", + "AboutRyujinxFormerMaintainersTitle": "이전 관리자 :", "AboutRyujinxMaintainersContentTooltipMessage": "클릭하면 기본 브라우저에서 기여자 페이지가 열립니다.", - "AboutRyujinxSupprtersTitle": "Patreon에서 후원 :", "AmiiboSeriesLabel": "Amiibo 시리즈", "AmiiboCharacterLabel": "캐릭터", "AmiiboScanButtonLabel": "스캔하기", @@ -690,6 +706,9 @@ "Never": "절대 안 함", "SwkbdMinCharacters": "{0}자 이상이어야 함", "SwkbdMinRangeCharacters": "{0}-{1}자 길이여야 함", + "CabinetTitle": "캐비닛 대화 상자", + "CabinetDialog": "Amiibo의 새 이름 입력하기", + "CabinetScanDialog": "지금 Amiibo를 스캔하세요.", "SoftwareKeyboard": "소프트웨어 키보드", "SoftwareKeyboardModeNumeric": "0-9 또는 '.'만 가능", "SoftwareKeyboardModeAlphabet": "CJK 문자가 아닌 문자만 가능", @@ -703,7 +722,6 @@ "UpdaterAddingFiles": "새 파일 추가...", "UpdaterExtracting": "업데이트 추출...", "UpdaterDownloading": "업데이트 내려받기 중...", - "Game": "게임", "Docked": "도킹", "Handheld": "휴대", "ConnectionError": "연결 오류가 발생했습니다.", @@ -767,14 +785,14 @@ "XCITrimmerDeselectDisplayed": "표시됨 선택 취소", "XCITrimmerSortName": "타이틀", "XCITrimmerSortSaved": "공간 절약s", - "XCITrimmerTrim": "Trim", - "XCITrimmerUntrim": "Untrim", + "XCITrimmerTrim": "트림", + "XCITrimmerUntrim": "언트림", "UpdateWindowUpdateAddedMessage": "{0}개의 새 업데이트가 추가됨", "UpdateWindowBundledContentNotice": "번들 업데이트는 제거할 수 없으며, 비활성화만 가능합니다.", "CheatWindowHeading": "{0} [{1}]에 사용 가능한 치트", "BuildId": "빌드ID:", "DlcWindowBundledContentNotice": "번들 DLC는 제거할 수 없으며 비활성화만 가능합니다.", - "DlcWindowHeading": "{1} ({2})에 내려받기 가능한 콘텐츠 {0}개 사용 가능", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0}개의 새로운 내려받기 가능한 콘텐츠가 추가됨", "AutoloadDlcAddedMessage": "{0}개의 새로운 내려받기 가능한 콘텐츠가 추가됨", "AutoloadDlcRemovedMessage": "{0}개의 내려받기 가능한 콘텐츠가 제거됨", diff --git a/src/Ryujinx/Assets/Locales/no_NO.json b/src/Ryujinx/Assets/Locales/no_NO.json new file mode 100644 index 000000000..b06a01130 --- /dev/null +++ b/src/Ryujinx/Assets/Locales/no_NO.json @@ -0,0 +1,791 @@ +{ + "Language": "Norsk", + "MenuBarFileOpenApplet": "Åpne Program", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Åpne Mii Redigerings program i eget vindu", + "SettingsTabInputDirectMouseAccess": "Direkte tilgang med Mus", + "SettingsTabSystemMemoryManagerMode": "Memory Manager-modus", + "SettingsTabSystemMemoryManagerModeSoftware": "Programvare", + "SettingsTabSystemMemoryManagerModeHost": "Vert (rask)", + "SettingsTabSystemMemoryManagerModeHostUnchecked": "Vert Ukontrollert (raskets, utrygt)", + "SettingsTabSystemUseHypervisor": "Bruk Hypervisor", + "MenuBarFile": "_Fil", + "MenuBarFileOpenFromFile": "_Last inn program fra fil", + "MenuBarFileOpenFromFileError": "Ingen apper ble funnet i valgt fil.", + "MenuBarFileOpenUnpacked": "Last inn _Upakket spill", + "MenuBarFileOpenEmuFolder": "Åpne Ryujinx mappe", + "MenuBarFileOpenLogsFolder": "Åpne Logg mappen", + "MenuBarFileExit": "_Avslutt", + "MenuBarOptions": "_Alternativer", + "MenuBarOptionsToggleFullscreen": "Fullskjermsvisning av/på", + "MenuBarOptionsStartGamesInFullscreen": "Start spill i Fullskjermmodus", + "MenuBarOptionsStopEmulation": "Stopp Emulering", + "MenuBarOptionsSettings": "_Innstillinger", + "MenuBarOptionsManageUserProfiles": "_Administrere Brukerprofiler", + "MenuBarActions": "_Handlinger", + "MenuBarOptionsSimulateWakeUpMessage": "Simuler oppvåknings-melding", + "MenuBarActionsScanAmiibo": "Skann en Amiibo", + "MenuBarTools": "_Verktøy", + "MenuBarToolsInstallFirmware": "Installer fastvare", + "MenuBarFileToolsInstallFirmwareFromFile": "Installer en fastvare fra XCI eller ZIP", + "MenuBarFileToolsInstallFirmwareFromDirectory": "Installer en fastvare fra en mappe", + "MenuBarToolsManageFileTypes": "Behandle filtyper", + "MenuBarToolsInstallFileTypes": "Installer filtyper", + "MenuBarToolsUninstallFileTypes": "Avinstaller filtyper", + "MenuBarView": "_Vis", + "MenuBarViewWindow": "Vindu størrelse", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Hjelp", + "MenuBarHelpCheckForUpdates": "Se etter oppdateringer", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", + "MenuBarHelpAbout": "Om", + "MenuSearch": "Søk ...", + "GameListHeaderFavorite": "Fav", + "GameListHeaderIcon": "Ikon", + "GameListHeaderApplication": "Navn", + "GameListHeaderDeveloper": "Utvikler", + "GameListHeaderVersion": "Versjon", + "GameListHeaderTimePlayed": "Spilletid", + "GameListHeaderLastPlayed": "Sist Spilt", + "GameListHeaderFileExtension": "Fil Eks.", + "GameListHeaderFileSize": "Fil Størrelse", + "GameListHeaderPath": "Bane", + "GameListContextMenuOpenUserSaveDirectory": "Åpne bruker lagrings mappe", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "Åpner mappen som inneholder programmets bruker lagring", + "GameListContextMenuOpenDeviceSaveDirectory": "Åpne lagringsmappe for enheten", + "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Åpner mappen som inneholder programmets lagringsenhet", + "GameListContextMenuOpenBcatSaveDirectory": "Åpne BCAT lagringsmappe", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Åpner mappen som inneholder programmets BCAT-lagring", + "GameListContextMenuManageTitleUpdates": "Administrer titteloppdateringer", + "GameListContextMenuManageTitleUpdatesToolTip": "Åpner vinduet Tittel - Oppdateringskontroll", + "GameListContextMenuManageDlc": "Administrer DLC", + "GameListContextMenuManageDlcToolTip": "Åpner DLC håndteringsvinduet", + "GameListContextMenuCacheManagement": "Cache administrasjon", + "GameListContextMenuCacheManagementPurgePptc": "Start PPTC gjenoppbygging", + "GameListContextMenuCacheManagementPurgePptcToolTip": "Utløs PPTC for å gjenoppbygge ved oppstart av neste spill-start", + "GameListContextMenuCacheManagementPurgeShaderCache": "Tøm shader cache", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Sletter applikasjonens shader cache", + "GameListContextMenuCacheManagementOpenPptcDirectory": "Åpne PPTC mappe", + "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Åpner mappen som inneholder programmets PPTC cache", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Åpne Shader Cache-mappen", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Åpner mappen som inneholder Programmets shader cache", + "GameListContextMenuExtractData": "Hent ut data", + "GameListContextMenuExtractDataExeFS": "ExeFS", + "GameListContextMenuExtractDataExeFSToolTip": "Pakk ut ExeFS seksjonen fra Programmets gjeldende konfigurasjon (inkludert oppdateringer)", + "GameListContextMenuExtractDataRomFS": "RomFS", + "GameListContextMenuExtractDataRomFSToolTip": "Pakk ut RomFS seksjonen fra applikasjonens gjeldende konfigurasjon (inkludert oppdateringer)", + "GameListContextMenuExtractDataLogo": "Logo", + "GameListContextMenuExtractDataLogoToolTip": "Pakk ut Logo-seksjonen fra applikasjonens gjeldende konfigurasjon (inkludert oppdateringer)", + "GameListContextMenuCreateShortcut": "Lag programsnarvei", + "GameListContextMenuCreateShortcutToolTip": "Lag en snarvei på skrivebordet som starter den valgte Applikasjonen", + "GameListContextMenuCreateShortcutToolTipMacOS": "Lag snarvei i macOSs Program-mappen som starter det valgte programmet", + "GameListContextMenuOpenModsDirectory": "Åpne Modifikasjonsmappen", + "GameListContextMenuOpenModsDirectoryToolTip": "Åpner mappen som inneholder programmets modifikasjoner", + "GameListContextMenuOpenSdModsDirectory": "Åpne Atmosfære modifikasjons mappen", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Åpner den alternative SD-kortets Atmosfære-mappe som inneholder programmoduser. Nyttig for modifikasjoner som er pakket for ekte maskinvare.", + "StatusBarGamesLoaded": "{0}/{1} Spill Lastet", + "StatusBarSystemVersion": "System versjon: {0}", + "LinuxVmMaxMapCountDialogTitle": "Lav grense for minnetildelinger oppdaget", + "LinuxVmMaxMapCountDialogTextPrimary": "Ønsker du å øke verdien av vm.max_map_count til {0}", + "LinuxVmMaxMapCountDialogTextSecondary": "Noen spill kan prøve å lage flere minnekartlegging enn det som er tillatt. Ryujinx vil krasjes så snart denne grensen overskrides.", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "Ja, frem til neste omstart", + "LinuxVmMaxMapCountDialogButtonPersistent": "Ja, permanent", + "LinuxVmMaxMapCountWarningTextPrimary": "Den maksimale mengden Minnetilordninger er lavere enn anbefalt.", + "LinuxVmMaxMapCountWarningTextSecondary": "Gjeldende verdi av vm.max_map_count ({0}) er lavere enn {1}. Noen spill kan prøve å lage flere minnedelinger enn det som er tillatt. Ryujinx vil kræsje så snart denne grensen overskrides.\n\nDet kan hende du ønsker å enten øke grensen eller installere pkexec manuelt, slik at Ryujinx kan hjelpe til med det.", + "Settings": "Innstillinger", + "SettingsTabGeneral": "Brukergrensesnitt", + "SettingsTabGeneralGeneral": "Generelt", + "SettingsTabGeneralEnableDiscordRichPresence": "Aktiver Discord Rik Tilstedeværelse", + "SettingsTabGeneralCheckUpdatesOnLaunch": "Se etter oppdateringer ved oppstart", + "SettingsTabGeneralShowConfirmExitDialog": "Vis \"Bekreft Avslutt\" vinduet", + "SettingsTabGeneralRememberWindowState": "Husk vinduets størrelse/posisjon", + "SettingsTabGeneralHideCursor": "Skjul musepeker:", + "SettingsTabGeneralHideCursorNever": "Aldri", + "SettingsTabGeneralHideCursorOnIdle": "Når inaktiv", + "SettingsTabGeneralHideCursorAlways": "Alltid", + "SettingsTabGeneralGameDirectories": "Spillmapper", + "SettingsTabGeneralAdd": "Legg til", + "SettingsTabGeneralRemove": "Fjern", + "SettingsTabSystem": "System", + "SettingsTabSystemCore": "Kjerne", + "SettingsTabSystemSystemRegion": "System region:", + "SettingsTabSystemSystemRegionJapan": "Japan", + "SettingsTabSystemSystemRegionUSA": "USA", + "SettingsTabSystemSystemRegionEurope": "Europa", + "SettingsTabSystemSystemRegionAustralia": "Australia", + "SettingsTabSystemSystemRegionChina": "Kina", + "SettingsTabSystemSystemRegionKorea": "Korea", + "SettingsTabSystemSystemRegionTaiwan": "Taiwan", + "SettingsTabSystemSystemLanguage": "Systemspråk", + "SettingsTabSystemSystemLanguageJapanese": "Japansk", + "SettingsTabSystemSystemLanguageAmericanEnglish": "Amerikansk engelsk", + "SettingsTabSystemSystemLanguageFrench": "Fransk", + "SettingsTabSystemSystemLanguageGerman": "Tysk", + "SettingsTabSystemSystemLanguageItalian": "Italiensk", + "SettingsTabSystemSystemLanguageSpanish": "Spansk", + "SettingsTabSystemSystemLanguageChinese": "Kinesisk", + "SettingsTabSystemSystemLanguageKorean": "Koreansk", + "SettingsTabSystemSystemLanguageDutch": "Nederlandsk", + "SettingsTabSystemSystemLanguagePortuguese": "Portugisisk", + "SettingsTabSystemSystemLanguageRussian": "Russisk", + "SettingsTabSystemSystemLanguageTaiwanese": "Taiwansk", + "SettingsTabSystemSystemLanguageBritishEnglish": "Britisk engelsk", + "SettingsTabSystemSystemLanguageCanadianFrench": "Canadisk Fransk", + "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Latinamerikansk spansk", + "SettingsTabSystemSystemLanguageSimplifiedChinese": "Forenklet kinesisk", + "SettingsTabSystemSystemLanguageTraditionalChinese": "Tradisjonell Kinesisk", + "SettingsTabSystemSystemTimeZone": "System Tidssone:", + "SettingsTabSystemSystemTime": "System tid:", + "SettingsTabSystemEnableVsync": "VSynk", + "SettingsTabSystemEnablePptc": "PPTC (Profilert Vedvarende Oversettelseshurtigbuffer)", + "SettingsTabSystemEnableFsIntegrityChecks": "FS Integritetssjekk", + "SettingsTabSystemAudioBackend": "Lyd Backend:", + "SettingsTabSystemAudioBackendDummy": "Dummy", + "SettingsTabSystemAudioBackendOpenAL": "OpenAL", + "SettingsTabSystemAudioBackendSoundIO": "Lyd Inn/Ut", + "SettingsTabSystemAudioBackendSDL2": "SDL2", + "SettingsTabSystemHacks": "Hacks", + "SettingsTabSystemHacksNote": "Kan forårsake ustabilitet", + "SettingsTabSystemExpandDramSize": "Utvid DRAM til 8GiB", + "SettingsTabSystemIgnoreMissingServices": "Ignorer manglende tjenester", + "SettingsTabGraphics": "Grafikk", + "SettingsTabGraphicsAPI": "Grafikk API", + "SettingsTabGraphicsEnableShaderCache": "Aktiver Shader Cachen", + "SettingsTabGraphicsAnisotropicFiltering": "Anisotropisk filtrering:", + "SettingsTabGraphicsAnisotropicFilteringAuto": "Automatisk", + "SettingsTabGraphicsAnisotropicFiltering2x": "2x", + "SettingsTabGraphicsAnisotropicFiltering4x": "4x", + "SettingsTabGraphicsAnisotropicFiltering8x": "8x", + "SettingsTabGraphicsAnisotropicFiltering16x": "16x", + "SettingsTabGraphicsResolutionScale": "Oppløsnings skala:", + "SettingsTabGraphicsResolutionScaleCustom": "Egendefinert (anbefales ikke)", + "SettingsTabGraphicsResolutionScaleNative": "Naturlig (720p/1080p)", + "SettingsTabGraphicsResolutionScale2x": "2 x (1440p/2160p)", + "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (anbefales ikke)", + "SettingsTabGraphicsAspectRatio": "Bildeformat", + "SettingsTabGraphicsAspectRatio4x3": "4:3", + "SettingsTabGraphicsAspectRatio16x9": "16:9", + "SettingsTabGraphicsAspectRatio16x10": "16:10", + "SettingsTabGraphicsAspectRatio21x9": "21:9", + "SettingsTabGraphicsAspectRatio32x9": "32:9", + "SettingsTabGraphicsAspectRatioStretch": "Strekk for og Tilpasse vindu", + "SettingsTabGraphicsDeveloperOptions": "Utvikleralternativer", + "SettingsTabGraphicsShaderDumpPath": "Grafikk Shader Dump bane:", + "SettingsTabLogging": "Logging", + "SettingsTabLoggingLogging": "Logging", + "SettingsTabLoggingEnableLoggingToFile": "Aktiver logging til fil", + "SettingsTabLoggingEnableStubLogs": "Aktiver Stub-logger", + "SettingsTabLoggingEnableInfoLogs": "Aktiver informasjonslogger", + "SettingsTabLoggingEnableWarningLogs": "Aktiver varsellogger", + "SettingsTabLoggingEnableErrorLogs": "Aktiver feillogger", + "SettingsTabLoggingEnableTraceLogs": "Aktiver spor logger", + "SettingsTabLoggingEnableGuestLogs": "Aktiver gjestelogger", + "SettingsTabLoggingEnableFsAccessLogs": "Aktiver Fs tilgangslogger", + "SettingsTabLoggingFsGlobalAccessLogMode": "Fs Global Access-logg-modus:", + "SettingsTabLoggingDeveloperOptions": "Utvikleralternativer", + "SettingsTabLoggingDeveloperOptionsNote": "Advarsel: Vil redusere ytelsen", + "SettingsTabLoggingGraphicsBackendLogLevel": "Grafikk Backend-loggnivå:", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "Ingen", + "SettingsTabLoggingGraphicsBackendLogLevelError": "Feil", + "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Tregere", + "SettingsTabLoggingGraphicsBackendLogLevelAll": "Alle", + "SettingsTabLoggingEnableDebugLogs": "Aktiver feilsøkingslogger", + "SettingsTabInput": "Inndata", + "SettingsTabInputEnableDockedMode": "Forankret modus", + "SettingsTabInputDirectKeyboardAccess": "Direkte tastaturtilgang", + "SettingsButtonSave": "Lagre", + "SettingsButtonClose": "Lukk", + "SettingsButtonOk": "OK", + "SettingsButtonCancel": "Avbryt", + "SettingsButtonApply": "Bruk", + "ControllerSettingsPlayer": "Spiller", + "ControllerSettingsPlayer1": "Spiller 1", + "ControllerSettingsPlayer2": "Spiller 2", + "ControllerSettingsPlayer3": "Spiller 3", + "ControllerSettingsPlayer4": "Spiller 4", + "ControllerSettingsPlayer5": "Spiller 5", + "ControllerSettingsPlayer6": "Spiller 6", + "ControllerSettingsPlayer7": "Spiller 7", + "ControllerSettingsPlayer8": "Spiller 8", + "ControllerSettingsHandheld": "Håndholdt", + "ControllerSettingsInputDevice": "Inndataenhet", + "ControllerSettingsRefresh": "Oppdater", + "ControllerSettingsDeviceDisabled": "Deaktivert", + "ControllerSettingsControllerType": "Kontrollertype", + "ControllerSettingsControllerTypeHandheld": "Håndholdt", + "ControllerSettingsControllerTypeProController": "Pro Controller", + "ControllerSettingsControllerTypeJoyConPair": "JoyCon Par", + "ControllerSettingsControllerTypeJoyConLeft": "JoyCon venstre", + "ControllerSettingsControllerTypeJoyConRight": "JoyCon høyre", + "ControllerSettingsProfile": "Profil", + "ControllerSettingsProfileDefault": "Standard", + "ControllerSettingsLoad": "Last", + "ControllerSettingsAdd": "Legg til", + "ControllerSettingsRemove": "Fjern", + "ControllerSettingsButtons": "Knapper", + "ControllerSettingsButtonA": "A", + "ControllerSettingsButtonB": "B", + "ControllerSettingsButtonX": "X", + "ControllerSettingsButtonY": "Y", + "ControllerSettingsButtonPlus": "+", + "ControllerSettingsButtonMinus": "-", + "ControllerSettingsDPad": "Retningsfelt", + "ControllerSettingsDPadUp": "Opp", + "ControllerSettingsDPadDown": "Ned", + "ControllerSettingsDPadLeft": "Venstre", + "ControllerSettingsDPadRight": "Høyre", + "ControllerSettingsStickButton": "Knapp", + "ControllerSettingsStickUp": "Opp", + "ControllerSettingsStickDown": "Ned", + "ControllerSettingsStickLeft": "Venstre", + "ControllerSettingsStickRight": "Høyre", + "ControllerSettingsStickStick": "Styrespak", + "ControllerSettingsStickInvertXAxis": "Inverter Styrespak X", + "ControllerSettingsStickInvertYAxis": "Inverter Styrespak Y", + "ControllerSettingsStickDeadzone": "Død sone:", + "ControllerSettingsLStick": "Venstre styrespak", + "ControllerSettingsRStick": "Høyre styrespak", + "ControllerSettingsTriggersLeft": "Utløsere venstre", + "ControllerSettingsTriggersRight": "Utløsere høyre", + "ControllerSettingsTriggersButtonsLeft": "Utløserknapper Venstre", + "ControllerSettingsTriggersButtonsRight": "Utløserknapper høyre", + "ControllerSettingsTriggers": "Utløsere", + "ControllerSettingsTriggerL": "L", + "ControllerSettingsTriggerR": "R", + "ControllerSettingsTriggerZL": "ZL", + "ControllerSettingsTriggerZR": "ZR", + "ControllerSettingsLeftSL": "SL", + "ControllerSettingsLeftSR": "SR", + "ControllerSettingsRightSL": "SL", + "ControllerSettingsRightSR": "SR", + "ControllerSettingsExtraButtonsLeft": "Knapper til venstre", + "ControllerSettingsExtraButtonsRight": "Knapper til høyre", + "ControllerSettingsMisc": "Diverse", + "ControllerSettingsTriggerThreshold": "Utløser terskel:", + "ControllerSettingsMotion": "Bevegelse", + "ControllerSettingsMotionUseCemuhookCompatibleMotion": "Bruk CemuHook kompatibel bevegelse", + "ControllerSettingsMotionControllerSlot": "Kontrollertype:", + "ControllerSettingsMotionMirrorInput": "Speilvend", + "ControllerSettingsMotionRightJoyConSlot": "Høyre JoyCon set:", + "ControllerSettingsMotionServerHost": "Server Vert:", + "ControllerSettingsMotionGyroSensitivity": "Gyro følsomhet:", + "ControllerSettingsMotionGyroDeadzone": "Gyro Dødsone:", + "ControllerSettingsSave": "Lagre", + "ControllerSettingsClose": "Lukk", + "KeyUnknown": "Ukjent", + "KeyShiftLeft": "Skift venstre", + "KeyShiftRight": "Skift høyre", + "KeyControlLeft": "Ctrl venstre", + "KeyMacControlLeft": "⌃ Venstre", + "KeyControlRight": "Ctrl høyre", + "KeyMacControlRight": "⌃ Høyre", + "KeyAltLeft": "Alt Venstre", + "KeyMacAltLeft": "⌥ Venstre", + "KeyAltRight": "Alt høyre", + "KeyMacAltRight": "⌥ Høyre", + "KeyWinLeft": "⊞ Venstre", + "KeyMacWinLeft": "⌘ Venstre", + "KeyWinRight": "⊞ Høyre", + "KeyMacWinRight": "⌘ Høyre", + "KeyMenu": "Meny", + "KeyUp": "Opp", + "KeyDown": "Ned", + "KeyLeft": "Venstre", + "KeyRight": "Høyre", + "KeyEnter": "Enter", + "KeyEscape": "Esc-tast", + "KeySpace": "Mellomrom", + "KeyTab": "Tab", + "KeyBackSpace": "Tilbaketast", + "KeyInsert": "Sett inn", + "KeyDelete": "Slett", + "KeyPageUp": "Side opp", + "KeyPageDown": "Side ned", + "KeyHome": "Hjem", + "KeyEnd": "Avslutt", + "KeyCapsLock": "Skiftelås", + "KeyScrollLock": "Rullelås", + "KeyPrintScreen": "Skjermbilde", + "KeyPause": "Stans midlertidig", + "KeyNumLock": "Numerisk Lås", + "KeyClear": "Tøm", + "KeyKeypad0": "Numerisk 0", + "KeyKeypad1": "Numerisk 1", + "KeyKeypad2": "Numerisk 2", + "KeyKeypad3": "Numerisk 3", + "KeyKeypad4": "Numerisk 4", + "KeyKeypad5": "Numerisk 5", + "KeyKeypad6": "Numerisk 6", + "KeyKeypad7": "Numerisk 7", + "KeyKeypad8": "Numerisk 8", + "KeyKeypad9": "Numerisk 9", + "KeyKeypadDivide": "Numerisk Dele", + "KeyKeypadMultiply": "Numerisk Multiplisere", + "KeyKeypadSubtract": "Numerisk Subtrakt", + "KeyKeypadAdd": "Numerisk Legg til", + "KeyKeypadDecimal": "Numerisk Desimal", + "KeyKeypadEnter": "Numerisk Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Ikke bundet", + "GamepadLeftStick": "Venstre Styrespak Trykk", + "GamepadRightStick": "R Styrespak Trykk", + "GamepadLeftShoulder": "Venstre Skulder", + "GamepadRightShoulder": "Høyre Skulder", + "GamepadLeftTrigger": "Venstre utløser", + "GamepadRightTrigger": "Høyre utløser", + "GamepadDpadUp": "Opp", + "GamepadDpadDown": "Ned", + "GamepadDpadLeft": "Venstre", + "GamepadDpadRight": "Høyre", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Veiledning", + "GamepadMisc1": "Diverse", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Berøringsplate", + "GamepadSingleLeftTrigger0": "Venstre utløser 0", + "GamepadSingleRightTrigger0": "Høyre utløser 0", + "GamepadSingleLeftTrigger1": "Venstre utløser 1", + "GamepadSingleRightTrigger1": "Høyre utløser 1", + "StickLeft": "Venstre styrespak", + "StickRight": "Høyre styrespak", + "UserProfilesSelectedUserProfile": "Valgt brukerprofil:", + "UserProfilesSaveProfileName": "Lagre profilnavnet", + "UserProfilesChangeProfileImage": "Endre profilbilde", + "UserProfilesAvailableUserProfiles": "Tilgjengelige brukerprofiler:", + "UserProfilesAddNewProfile": "Opprett Profil", + "UserProfilesDelete": "Slett", + "UserProfilesClose": "Lukk", + "ProfileNameSelectionWatermark": "Velg ett kallenavn", + "ProfileImageSelectionTitle": "Valg av profilbilde", + "ProfileImageSelectionHeader": "Velg et profilbilde", + "ProfileImageSelectionNote": "Du kan importere et tilpasset profilbilde, eller velge en avatar fra system fastvare", + "ProfileImageSelectionImportImage": "Importer bildefil", + "ProfileImageSelectionSelectAvatar": "Velg fastvare profilbilde", + "InputDialogTitle": "Input Dialog", + "InputDialogOk": "OK", + "InputDialogCancel": "Avbryt", + "InputDialogAddNewProfileTitle": "Velg profilnavnet", + "InputDialogAddNewProfileHeader": "Vennligst skriv inn et profilnavn", + "InputDialogAddNewProfileSubtext": "(Maks lengde: {0})", + "AvatarChoose": "Velg profilbilde", + "AvatarSetBackgroundColor": "Angi bakgrunnsfarge", + "AvatarClose": "Lukk", + "ControllerSettingsLoadProfileToolTip": "Last inn profil", + "ControllerSettingsAddProfileToolTip": "Legg til profil", + "ControllerSettingsRemoveProfileToolTip": "Fjern profil", + "ControllerSettingsSaveProfileToolTip": "Lagre Profil", + "MenuBarFileToolsTakeScreenshot": "Ta skjermbilde", + "MenuBarFileToolsHideUi": "Skjul brukergrensesnitt", + "GameListContextMenuRunApplication": "Kjør programmet", + "GameListContextMenuToggleFavorite": "Vis/Skjul favoritter", + "GameListContextMenuToggleFavoriteToolTip": "Vis/Skjul favorittstatus for spillet", + "SettingsTabGeneralTheme": "Tema:", + "SettingsTabGeneralThemeAuto": "Automatisk", + "SettingsTabGeneralThemeDark": "Mørk", + "SettingsTabGeneralThemeLight": "Lys", + "ControllerSettingsConfigureGeneral": "Konfigurer", + "ControllerSettingsRumble": "Vibrasjon", + "ControllerSettingsRumbleStrongMultiplier": "Sterk Vibrasjon multiplikator", + "ControllerSettingsRumbleWeakMultiplier": "Svak Vibrasjon multiplikator", + "DialogMessageSaveNotAvailableMessage": "Det er ingen lagrede data for {0} [{1:x16}]", + "DialogMessageSaveNotAvailableCreateSaveMessage": "Vil du lage lagrede data for dette spillet", + "DialogConfirmationTitle": "Ryujinx - Bekreftelse", + "DialogUpdaterTitle": "Ryujinx – Oppdaterer", + "DialogErrorTitle": "Ryujinx - Feil", + "DialogWarningTitle": "Ryujinx - Advarsel", + "DialogExitTitle": "Ryujinx - Avslutt", + "DialogErrorMessage": "Ryujinx har støtt på ett problem", + "DialogExitMessage": "Er du sikker på at du ønsker å lukke Ryujinx?", + "DialogExitSubMessage": "Alle ulagrede data vil gå tapt!", + "DialogMessageCreateSaveErrorMessage": "Det oppstod en feil under oppretting av den angitte lagredata: {0}", + "DialogMessageFindSaveErrorMessage": "Det oppstod en feil under oppretting av den angitte lagredata: {0}", + "FolderDialogExtractTitle": "Velg mappen å pakke ut i", + "DialogNcaExtractionMessage": "Trekker ut {0} seksjonen fra {1}...", + "DialogNcaExtractionTitle": "Ryujinx - NCA Seksjon Ekstraktor", + "DialogNcaExtractionMainNcaNotFoundErrorMessage": "Uttrekksfeil. Hoveddelen av NCA var ikke tilstede i valgt fil.", + "DialogNcaExtractionCheckLogErrorMessage": "Uttrekkingsfeil. Les loggfilen for mer informasjon.", + "DialogNcaExtractionSuccessMessage": "Utvinningen er fullført.", + "DialogUpdaterConvertFailedMessage": "Kunne ikke konvertere gjeldende Ryujinx-versjon.", + "DialogUpdaterCancelUpdateMessage": "Avbryter oppdatering!", + "DialogUpdaterAlreadyOnLatestVersionMessage": "Du bruker allerede den nyeste versjonen av Ryujinx!", + "DialogUpdaterFailedToGetVersionMessage": "En feil oppstod ved forsøk på å få utgivelsesinformasjon fra GitHub Utgivelse. Dette kan forårsakes hvis en ny utgave blir samlet av GitHub Handlinger. Prøv igjen om noen minutter.", + "DialogUpdaterConvertFailedGithubMessage": "Kan ikke konvertere mottatt Ryujinx-versjon fra Github Utgivelse.", + "DialogUpdaterDownloadingMessage": "Laster ned oppdatering...", + "DialogUpdaterExtractionMessage": "Pakker ut oppdatering...", + "DialogUpdaterRenamingMessage": "Endrer navn på oppdatering...", + "DialogUpdaterAddingFilesMessage": "Legger til ny oppdatering...", + "DialogUpdaterCompleteMessage": "Oppdateringen er fullført!", + "DialogUpdaterRestartMessage": "Vil du starte Ryujinx på nytt nå?", + "DialogUpdaterNoInternetMessage": "Du er ikke tilkoblet internett", + "DialogUpdaterNoInternetSubMessage": "Kontroller at du har en fungerende Internett-tilkobling!", + "DialogUpdaterDirtyBuildMessage": "Du kan ikke oppdatere en skitten versjon av Ryujinx!", + "DialogUpdaterDirtyBuildSubMessage": "Vennligst last ned Ryujinx på https://ryujinx.org/ hvis du ser etter en støttet versjon.", + "DialogRestartRequiredMessage": "Omstart Kreves", + "DialogThemeRestartMessage": "Temaet har blitt lagret. En omstart kreves for å bruke temaet.", + "DialogThemeRestartSubMessage": "Vil du starte på nytt", + "DialogFirmwareInstallEmbeddedMessage": "Ønsker du å installere fastvaren innebygd i dette spillet? (Firmware {0})", + "DialogFirmwareInstallEmbeddedSuccessMessage": "Det ble ikke funnet noen installert fastvare, men Ryujinx kunne installere fastvare {0} fra det oppgitte spillet.\nemulatoren vil nå starte.", + "DialogFirmwareNoFirmwareInstalledMessage": "Ingen fastvare installert", + "DialogFirmwareInstalledMessage": "fastvare {0} ble installert", + "DialogInstallFileTypesSuccessMessage": "Filtyper ble installert!", + "DialogInstallFileTypesErrorMessage": "Kunne ikke installere filtyper.", + "DialogUninstallFileTypesSuccessMessage": "Filtyper ble avinstallert!", + "DialogUninstallFileTypesErrorMessage": "Kunne ikke avinstallere filtyper.", + "DialogOpenSettingsWindowLabel": "Åpne innstillinger-vinduet", + "DialogControllerAppletTitle": "Kontroller Applet", + "DialogMessageDialogErrorExceptionMessage": "Feil ved visning av meldings-dialog: {0}", + "DialogSoftwareKeyboardErrorExceptionMessage": "Feil ved visning av programvaretastatur: {0}", + "DialogErrorAppletErrorExceptionMessage": "Feil ved visning av Feilmeldingsdialog: {0}", + "DialogUserErrorDialogMessage": "{0}: {1}", + "DialogUserErrorDialogInfoMessage": "\nFor mer informasjon om hvordan du fikser denne feilen, følg vår oppsettsveiledning.", + "DialogUserErrorDialogTitle": "Ryujinx Feilmelding ({0})", + "DialogAmiiboApiTitle": "Amiibo API", + "DialogAmiiboApiFailFetchMessage": "En feil oppstod under henting av informasjon fra API.", + "DialogAmiiboApiConnectErrorMessage": "Kan ikke koble til Amiibo API server. Tjenesten kan være nede, eller du må kanskje verifisere at din internettforbindelse er tilkoblet.", + "DialogProfileInvalidProfileErrorMessage": "Profil {0} er ikke kompatibel med den gjeldende inndata konfigurasjonen", + "DialogProfileDefaultProfileOverwriteErrorMessage": "Standard profil kan ikke overskrives", + "DialogProfileDeleteProfileTitle": "Sletter profil", + "DialogProfileDeleteProfileMessage": "Denne handlingen er irreversibel, er du sikker på at du vil fortsette?", + "DialogWarning": "Advarsel", + "DialogPPTCDeletionMessage": "Du er i ferd med å bygge en PPTC i køen ved neste oppstart av:\n\n{0}\n\nEr du sikker på at du vil fortsette?", + "DialogPPTCDeletionErrorMessage": "Feil under rensing av PPTC cache ved {0}: {1}", + "DialogShaderDeletionMessage": "Du er i ferd med å slette Shader cachen for :\n\n{0}\n\nEr du sikker på at du vil fortsette?", + "DialogShaderDeletionErrorMessage": "Feil under tømming av Shader cache ved {0}: {1}", + "DialogRyujinxErrorMessage": "Ryujinx har støtt på ett problem", + "DialogInvalidTitleIdErrorMessage": "UI-feil: Det valgte spillet har ikke en gyldig tittel-ID", + "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "En gyldig systemfastvare ble ikke funnet i {0}.", + "DialogFirmwareInstallerFirmwareInstallTitle": "Installer fastvare {0}", + "DialogFirmwareInstallerFirmwareInstallMessage": "Systemversjon {0} vil bli installert.", + "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nDette erstatter den gjeldende systemversjonen {0}.", + "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "Vil du fortsette?", + "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installerer fastvare...", + "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Systemversjon {0} ble installert.", + "DialogUserProfileDeletionWarningMessage": "Det vil ikke være noen profiler å åpnes hvis valgt profil blir slettet", + "DialogUserProfileDeletionConfirmMessage": "Vil du slette den valgte profilen", + "DialogUserProfileUnsavedChangesTitle": "Advarsel - Ulagrede endringer", + "DialogUserProfileUnsavedChangesMessage": "Du har gjort endringer i denne brukerprofilen som ikke er lagret.", + "DialogUserProfileUnsavedChangesSubMessage": "Vil du forkaste endringene dine?", + "DialogControllerSettingsModifiedConfirmMessage": "Innstillinger for gjeldende kontroller har blitt oppdatert.", + "DialogControllerSettingsModifiedConfirmSubMessage": "Vil du lagre?", + "DialogLoadFileErrorMessage": "{0}. Feilet fil: {1}", + "DialogModAlreadyExistsMessage": "Modifikasjon eksisterer allerede", + "DialogModInvalidMessage": "Den angitte mappen inneholder ikke en modifikasjon!", + "DialogModDeleteNoParentMessage": "Kunne ikke slette: Fant ikke overordnet mappe for mod \"{0}\"!", + "DialogDlcNoDlcErrorMessage": "Den angitte filen inneholder ikke en DLC for den valgte tittelen!", + "DialogPerformanceCheckLoggingEnabledMessage": "Du har sporing aktivert, noe som er designet til å bli brukt av utviklere.", + "DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal ytelse er det anbefalt å deaktivere spor-logging. Ønsker du å deaktivere spor-logging nå?", + "DialogPerformanceCheckShaderDumpEnabledMessage": "Du har aktiv dumping av shader, som bare er laget for å brukes av utviklere.", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "For optimal ytelse er det anbefalt å deaktivere dumping. Ønsker du å deaktivere shader dumping nå?", + "DialogLoadAppGameAlreadyLoadedMessage": "Et spill er allerede lastet inn", + "DialogLoadAppGameAlreadyLoadedSubMessage": "Slutt å emulere eller lukk emulatoren før du starter et annet spill.", + "DialogUpdateAddUpdateErrorMessage": "Den angitte filen inneholder ikke en oppdatering for den valgte tittelen!", + "DialogSettingsBackendThreadingWarningTitle": "Advarsel - Backend Tråd", + "DialogSettingsBackendThreadingWarningMessage": "Ryujinx må startes på nytt etter at dette alternativet er endret slik at det tas i bruk helt. Avhengig av plattformen din, må du kanskje manuelt skru av driveren's egen flertråder når du bruker Ryujinx's.", + "DialogModManagerDeletionWarningMessage": "Du er i ferd med å slette modifikasjonen: {0}\n\ner du sikker på at du vil fortsette?", + "DialogModManagerDeletionAllWarningMessage": "Du er i ferd med å slette alle modifikasjonene for denne tittelen: {0}\n\ner du sikker på at du vil fortsette?", + "SettingsTabGraphicsFeaturesOptions": "Funksjoner", + "SettingsTabGraphicsBackendMultithreading": "Grafikk Backend Fleroppgavekjøring", + "CommonAuto": "Automatisk", + "CommonOff": "Av", + "CommonOn": "På", + "InputDialogYes": "Ja", + "InputDialogNo": "Nei", + "DialogProfileInvalidProfileNameErrorMessage": "Filnavnet inneholder ugyldige tegn. Prøv på nytt.", + "MenuBarOptionsPauseEmulation": "Stans midlertidig", + "MenuBarOptionsResumeEmulation": "Gjenoppta", + "AboutUrlTooltipMessage": "Klikk for å åpne Ryujinx nettsiden i din standardnettleser.", + "AboutDisclaimerMessage": "Ryujinx er ikke knyttet til NintendoTM,\neller noen av samarbeidspartnerne sine, på noen som helst måte.", + "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) brukes sammen med\ni vår Amiibo-emulsjon.", + "AboutPatreonUrlTooltipMessage": "Klikk for å åpne Ryujinx Patreon-siden i din standardnettleser.", + "AboutGithubUrlTooltipMessage": "Klikk for å åpne Ryujinx GitHub siden i din standardnettleser.", + "AboutDiscordUrlTooltipMessage": "Klikk for å åpne en invitasjon til Ryujinx Discord-serveren i nettleseren din.", + "AboutTwitterUrlTooltipMessage": "Klikk for å åpne Ryujinx Twitter-siden i din standardnettleser.", + "AboutRyujinxAboutTitle": "Om:", + "AboutRyujinxAboutContent": "Ryujinx er en emulator for Nintendo SwitchTM.\nVennligst støtt oss på Patreon.\nFå alle de siste nyhetene på vår Twitter eller Discord.\nUtviklere som er interessert i å bidra kan finne ut mer på GitHub eller Discord.", + "AboutRyujinxMaintainersTitle": "Vedlikeholdt av:", + "AboutRyujinxMaintainersContentTooltipMessage": "Klikk for å åpne Bidragsyter-siden i standardleseren din.", + "AboutRyujinxSupprtersTitle": "Støttet på Patreon av:", + "AmiiboSeriesLabel": "Amibo Serie", + "AmiiboCharacterLabel": "Karakter", + "AmiiboScanButtonLabel": "Skanne det", + "AmiiboOptionsShowAllLabel": "Vis alle Amiibo", + "AmiiboOptionsUsRandomTagLabel": "Hack: Bruk tilfeldig tag-Uuid", + "DlcManagerTableHeadingEnabledLabel": "Aktivert", + "DlcManagerTableHeadingTitleIdLabel": "Tittel ID", + "DlcManagerTableHeadingContainerPathLabel": "Beholder bane", + "DlcManagerTableHeadingFullPathLabel": "Fullstendig bane", + "DlcManagerRemoveAllButton": "Fjern alle", + "DlcManagerEnableAllButton": "Aktiver alle", + "DlcManagerDisableAllButton": "Deaktiver alle", + "ModManagerDeleteAllButton": "Slett alt", + "MenuBarOptionsChangeLanguage": "Endre språk", + "MenuBarShowFileTypes": "Vis Filtyper", + "CommonSort": "Sorter", + "CommonShowNames": "Vis navn", + "CommonFavorite": "Favoritt", + "OrderAscending": "Stigende", + "OrderDescending": "Synkende", + "SettingsTabGraphicsFeatures": "Funksjoner & forbedringer", + "ErrorWindowTitle": "Feilvindu", + "ToggleDiscordTooltip": "Velg om Ryujinx skal vises på din \"spillende\" Discord aktivitet eller ikke", + "AddGameDirBoxTooltip": "Angi en spillmappe for å legge til i listen", + "AddGameDirTooltip": "Legg til en spillmappe i listen", + "RemoveGameDirTooltip": "Fjern valgt spillmappe", + "CustomThemeCheckTooltip": "Bruk et egendefinert Avalonia tema for GUI for å endre utseende til emulatormenyene", + "CustomThemePathTooltip": "Bane til egendefinert GUI-tema", + "CustomThemeBrowseTooltip": "Søk etter et egendefinert GUI-tema", + "DockModeToggleTooltip": "Forankret modus gjør at systemet oppføre seg som en forankret Nintendo Switch. Dette forbedrer grafikkkvaliteten i de fleste spill. Motsatt vil deaktivering av dette gjøre at systemet oppføre seg som en håndholdt Nintendo Switch, noe som reduserer grafikkkvaliteten.\n\nKonfigurer spiller 1 kontroller hvis du planlegger å bruke forankret modus; konfigurer håndholdte kontroller hvis du planlegger å bruke håndholdte modus.\n\nLa PÅ hvis du er usikker.", + "DirectKeyboardTooltip": "Direkte tastaturtilgang (HID) støtte. Gir deg spill-tilgang til tastaturet som en tekstinnlegg-enhet.\n\nfungerer kun med spill som lokalt støtter tastaturbruk på Ninteno SwitchTM maskinvare.\n\nLa være AV hvis du er usikker.", + "DirectMouseTooltip": "Direkte musepeker (HID) støtte. Gir deg spill-tilgang til musepeker.\n\nfungerer kun med spill som lokalt støtter musepekere på Ninteno SwitchTM maskinvare.\n\nNår aktivert, kan det hende touch funksjoner ikke fungerer\n\nLa være AV hvis du er usikker.", + "RegionTooltip": "Endre systemregion", + "LanguageTooltip": "Endre systemspråk", + "TimezoneTooltip": "Endre systemtidssone", + "TimeTooltip": "Endre systemtid", + "VSyncToggleTooltip": "Emuler konsollens loddrett synkronisering. på ett vis en bildefrekvens begrensning for de fleste spill; deaktivering kan få spill til å kjøre med høyere hastighet, eller til å laste skjermene tar lengre tid eller sitter fast.\n\nkan byttes inn i spillet med en hurtigtast for preferansen (F1 som standard). Vi anbefaler å gjøre dette hvis du planlegger å deaktivere dette.\n\nLa være PÅ hvis du er usikker.", + "PptcToggleTooltip": "Lagrer oversatte JIT funksjoner så de ikke trenger og bli oversatt hver gang spillet laster.\n\nKan redusere hakkete spilling og gjør at spillet starter opp raskere ved første oppstart.\n\nLa være PÅ om usikker.", + "FsIntegrityToggleTooltip": "Sjekker for korrupte filer ved oppstart av et spill, og dersom korrupte filer oppdages, viser en hashfeil i loggen.\n\nhar ingen innvirkning på ytelsen og er ment å hjelpe med feilsøking.\n\nLa være PÅ hvis usikker.", + "AudioBackendTooltip": "Endrer backend brukt til å gjengi lyd.\n\nSDL2 er foretrukket, mens OpenAL og SoundIO brukes som reserveløsning. Dummy kommer ikke til å ha lyd.\n\nSett til SDL2 hvis usikker.", + "MemoryManagerTooltip": "Endre hvordan gjesteminne tilordnes og åpnes. Påvirker emulator CPU-ytelsen veldig mye.\n\nSett til HOST UNCHECKED hvis usikker.", + "MemoryManagerSoftwareTooltip": "Bruk en programvareside tabell for adresseoversettelse. Høyeste nøyaktighet, men tregeste ytelse.", + "MemoryManagerHostTooltip": "Direkte kartminne i vertens adresseområde. Mye raskere JIT kompilering og utførelse.", + "MemoryManagerUnsafeTooltip": "Direkte kartminne, men ikke masker adressen i gjesteadressen før du har tilgang. raskere, men på bekostning av sikkerhet. gjeste-programmet kan få tilgang til minne fra hvor som helst i Ryujinx, så bare kjøre programmer du stoler på med denne modusen.", + "UseHypervisorTooltip": "Bruk Hypervisor i stedet for JIT. Det øker ytelsen mye hvis det er tilgjengelig, men det kan være ustabilt i den nåværende tilstanden.", + "DRamTooltip": "Bruker en alternativ minnemodus med 8GiB i DRAM for og etterligne Switch utvikler modeller.\n\nDette er bare nyttig for teksturpakker eller 4k oppløsningsmoduler. Forbedrer IKKE ytelsen.\n\nLa AV hvis usikker.", + "IgnoreMissingServicesTooltip": "Ignorerer ikke implementerte Horisont OS-tjenester. Dette kan hjelpe med å omgå krasj ved oppstart av enkelte spill.\n\nLa AV hvis du er usikker.", + "GraphicsBackendThreadingTooltip": "Utfører grafikkbackend kommandoer på en annen tråd.\n\nØker hastigheten for shaderkomprimering, reduserer hakking og forbedrer ytelsen til GPU-drivere uten å spre støtten fra sine egne. Litt bedre ytelse på drivere med flertråd.\n\nSett for å AUTO hvis usikker.", + "GalThreadingTooltip": "Utfører grafikkbackend kommandoer på en annen tråd.\n\nØker hastigheten for shaderkomprimering, reduserer hakking og forbedrer ytelsen til GPU-drivere uten flertråd støtte. Litt bedre ytelse på drivere med flertråd.\n\nSett for å AUTO hvis usikker.", + "ShaderCacheToggleTooltip": "Lagrer en disk shader cache som reduserer hakking jo flere ganger du spiller.\n\nLa være PÅ om usikker.", + "ResolutionScaleTooltip": "Dobler spillets gjengivelse.\n\nNoen få spill fungerer kanskje ikke med dette aktivert og kan se veldig pikselert ut selv når gjengivelsen er økt; for de spillene, så kan det hende du må bruke modifikasjoner som fjerner anti-aliasing eller som øker den interne gjengivelsen. For og bruke sistnenvte, så vil du helst bruke \"Native\".\n\nHa til tanke at 4x er unødig for virituelt alle maskiner.", + "ResolutionScaleEntryTooltip": "Det er mer sannsynlig at flytende punktoppløsning skalaer som 1.5. Ikke-integrerte skalaer forårsaker problemer eller krasj.", + "AnisotropyTooltip": "Nivå av Anisotropisk filtrering. Sett til Auto for å bruke verdien som kreves av spillet.", + "AspectRatioTooltip": "Sideforhold angitt til gjengitt vindu.\n\nBare bytt dette om du bruker en modifikasjon som forandrer Sideforholdet på spillet ditt, ellers vil grafikken bli strukket.\n\nLa være på 16:9 om usikker.", + "ShaderDumpPathTooltip": "Grafikk Shader Dump bane", + "FileLogTooltip": "Lagrer konsoll-logging til en loggfil på harddisken. Påvirker ikke ytelsen.", + "StubLogTooltip": "Skriver ut log meldinger i konsollen. Påvirker ikke ytelsen.", + "InfoLogTooltip": "Skriver ut info loggmeldinger i konsollen. Påvirker ikke ytelse.", + "WarnLogTooltip": "Skriver ut varselloggmeldinger i konsollen. påvirker ikke ytelsen.", + "ErrorLogTooltip": "Skriver ut feilloggmeldinger i konsollen. Påvirker ikke ytelse.", + "TraceLogTooltip": "Skriver ut sporbare loggmeldinger i konsollen. påvirker ikke ytelsen.", + "GuestLogTooltip": "Skriver ut gjesteloggmeldinger i konsollen. påvirker ikke ytelsen.", + "FileAccessLogTooltip": "Skriver ut filtilgang til loggmeldinger i konsollen.", + "FSAccessLogModeTooltip": "Aktiverer FS tilgang loggutgang til konsollen. Mulige moduser er 0-3", + "DeveloperOptionTooltip": "Bruk med forsiktighet", + "OpenGlLogLevel": "Krever riktige loggnivåer aktivert", + "DebugLogTooltip": "Skriver ut loggmeldinger i konsollen.\n\nBruk bare dette hvis et medlem har gitt spesifikke instruksjoner, siden det vil gjøre loggene vanskelig å lese og forverre emulatorytelse.", + "LoadApplicationFileTooltip": "Åpne filutforsker for å velge en Switch kompatibel fil å laste", + "LoadApplicationFolderTooltip": "Åpne en filutforsker for å velge en Switch kompatibel, upakket applikasjon for å laste", + "OpenRyujinxFolderTooltip": "Åpne Ryujinx filsystem-mappen", + "OpenRyujinxLogsTooltip": "Åpner mappen hvor logger er lagret", + "ExitTooltip": "Avslutt Ryujinx", + "OpenSettingsTooltip": "Åpne innstillinger-vinduet", + "OpenProfileManagerTooltip": "Åpne vindu for brukerprofiler", + "StopEmulationTooltip": "Stopp emuleringen av dette spillet og gå tilbake til spill valg", + "CheckUpdatesTooltip": "Se etter oppdateringer til Ryujinx", + "OpenAboutTooltip": "Åpne Om Vindu", + "GridSize": "Rutenett størrelse", + "GridSizeTooltip": "Endre størrelsen på rutenettet elementer", + "SettingsTabSystemSystemLanguageBrazilianPortuguese": "Brasiliansk portugisisk", + "AboutRyujinxContributorsButtonHeader": "Se alle bidragsytere", + "SettingsTabSystemAudioVolume": "Lydnivå: ", + "AudioVolumeTooltip": "Endre lydenivå", + "SettingsTabSystemEnableInternetAccess": "Internett-tilgang for gjeste/LAN-modus", + "EnableInternetAccessTooltip": "Tillater emulert applikasjon å koble til Internett.\n\nSpill med en LAN-modus kan koble til hverandre når dette er aktivert og systemene er koblet til det samme tilgangspunktet. Dette inkluderer ekte konsoller også.\n\ntillater IKKE tilkobling til Nintendo servere. Kan forårsake krasjing i enkelte spill som prøver å koble til Internett.\n\nLa stå AV hvis du er usikker.", + "GameListContextMenuManageCheatToolTip": "Administrer juksemoduser", + "GameListContextMenuManageCheat": "Administrer juksemoduser", + "GameListContextMenuManageModToolTip": "Administrer modifikasjoner", + "GameListContextMenuManageMod": "Administrer modifikasjoner", + "ControllerSettingsStickRange": "Omfang:", + "DialogStopEmulationTitle": "Ryujinx - Stopp emulasjon", + "DialogStopEmulationMessage": "Er du sikker på at du vil stoppe emulasjonen?", + "SettingsTabCpu": "Prosessor", + "SettingsTabAudio": "Lyd", + "SettingsTabNetwork": "Nettverk", + "SettingsTabNetworkConnection": "Nettverk tilkobling", + "SettingsTabCpuCache": "CPU-buffer", + "SettingsTabCpuMemory": "Prosessor modus", + "DialogUpdaterFlatpakNotSupportedMessage": "Vennligst oppdater Ryujinx via FlatHub.", + "UpdaterDisabledWarningTitle": "Oppdatering Deaktivert!", + "ControllerSettingsRotate90": "Roter 90° med klokken", + "IconSize": "Ikon størrelse", + "IconSizeTooltip": "Endre størrelsen på spillikonene", + "MenuBarOptionsShowConsole": "Vis konsoll", + "ShaderCachePurgeError": "Feil under tømming av shader cache ved {0}: {1}", + "UserErrorNoKeys": "Finner ikke nøkler", + "UserErrorNoFirmware": "Fastvare ikke funnet", + "UserErrorFirmwareParsingFailed": "Fastvare analysefeil", + "UserErrorApplicationNotFound": "Applikasjon ikke funnet", + "UserErrorUnknown": "Ukjent feil", + "UserErrorUndefined": "Udefinert feil", + "UserErrorNoKeysDescription": "Ryujinx kunne ikke finne 'prod.keys' filen din", + "UserErrorNoFirmwareDescription": "Ryujinx kunne ikke finne noen fastvare installert", + "UserErrorFirmwareParsingFailedDescription": "Ryujinx klarte ikke å analysere levert fastvare. Dette er vanligvis forårsaket av utdaterte nøkler.", + "UserErrorApplicationNotFoundDescription": "Ryujinx kunne ikke finne en gyldig applikasjon på den gitte banen.", + "UserErrorUnknownDescription": "En ukjent feil oppstod!", + "UserErrorUndefinedDescription": "En udefinert feil oppstod! Dette burde ikke skje, vennligst kontakt en utvikler!", + "OpenSetupGuideMessage": "Åpne oppsettsveiledningen", + "NoUpdate": "Ingen oppdatering", + "TitleUpdateVersionLabel": "Versjon {0}", + "TitleBundledUpdateVersionLabel": "Pakket: Versjon {0}", + "TitleBundledDlcLabel": "Pakket:", + "RyujinxInfo": "Ryujinx - Informasjon", + "RyujinxConfirm": "Ryujinx - Bekreftelse", + "FileDialogAllTypes": "Alle typer", + "Never": "Aldri", + "SwkbdMinCharacters": "Må være minimum {0} tegn lang", + "SwkbdMinRangeCharacters": "Må være {0}-{1} tegn", + "SoftwareKeyboard": "Programvare Tastatur", + "SoftwareKeyboardModeNumeric": "Må kun være 0-9 eller '.'", + "SoftwareKeyboardModeAlphabet": "Må kun være uten CJK-tegn", + "SoftwareKeyboardModeASCII": "Må være kun ASCII-tekst", + "ControllerAppletControllers": "Støttede kontrollere:", + "ControllerAppletPlayers": "Spillere:", + "ControllerAppletDescription": "Din nåværende konfigurasjon er ugyldig. Åpne innstillinger og konfigurer inndata.", + "ControllerAppletDocked": "Docked modus. Håndholdt kontroll skal være deaktivert.", + "UpdaterRenaming": "Omdøper gamle filer...", + "UpdaterRenameFailed": "Oppdateringen kunne ikke gi filen nytt navn: {0}", + "UpdaterAddingFiles": "Legger til nye filer...", + "UpdaterExtracting": "Pakker ut oppdatering...", + "UpdaterDownloading": "Laster ned oppdatering...", + "Game": "Spill", + "Docked": "Forankret", + "Handheld": "Håndholdt", + "ConnectionError": "Tilkoblingsfeil", + "AboutPageDeveloperListMore": "{0} og mer...", + "ApiError": "API feil.", + "LoadingHeading": "Laster {0}", + "CompilingPPTC": "Sammensetter PTC", + "CompilingShaders": "Samler Shaders", + "AllKeyboards": "Alle tastaturer", + "OpenFileDialogTitle": "Velg en støttet fil for å åpne", + "OpenFolderDialogTitle": "Velg en mappe med et pakket ut spill", + "AllSupportedFormats": "Alle støttede formater", + "RyujinxUpdater": "Ryujinx Oppgradering", + "SettingsTabHotkeys": "Hurtigtaster for tastatur", + "SettingsTabHotkeysHotkeys": "Hurtigtaster for tastatur", + "SettingsTabHotkeysToggleVsyncHotkey": "Aktiver/deaktiver VSync:", + "SettingsTabHotkeysScreenshotHotkey": "Skjermbilde", + "SettingsTabHotkeysShowUiHotkey": "Vis UI:", + "SettingsTabHotkeysPauseHotkey": "Stans midlertidig:", + "SettingsTabHotkeysToggleMuteHotkey": "Demp:", + "ControllerMotionTitle": "Innstillinger for bevegelses kontroll", + "ControllerRumbleTitle": "Innstillinger for Vibrasjon", + "SettingsSelectThemeFileDialogTitle": "Velg tema fil", + "SettingsXamlThemeFile": "Xaml tema-fil", + "AvatarWindowTitle": "Administrer kontoer - Profilbilde", + "Amiibo": "Amiibo", + "Unknown": "Ukjent", + "Usage": "Forbruk", + "Writable": "Skrivbart", + "SelectDlcDialogTitle": "Velg DLC-filer", + "SelectUpdateDialogTitle": "Velg oppdateringsfiler", + "SelectModDialogTitle": "Velg modifikasjons mappe", + "UserProfileWindowTitle": "Bruker Profiler Behandler", + "CheatWindowTitle": "Juksing behandler", + "DlcWindowTitle": "Behandle nedlastbart innhold for {0} ({1})", + "ModWindowTitle": "Administrere Modifikasjoner for {0} ({1})", + "UpdateWindowTitle": "Tittel oppdatering behandler", + "CheatWindowHeading": "Juks tilgjengelig for {0} [{1}]", + "BuildId": "VersjonsId:", + "DlcWindowHeading": "{0} Nedlastbare innhold(er)", + "ModWindowHeading": "{0} Modifikasjoner(s)", + "UserProfilesEditProfile": "Rediger Valgte", + "Cancel": "Avbryt", + "Save": "Lagre", + "Discard": "Forkast", + "Paused": "Satt på pause", + "UserProfilesSetProfileImage": "Angi profilbilde", + "UserProfileEmptyNameError": "Navn er påkrevd", + "UserProfileNoImageError": "Profilbilde må være angitt", + "GameUpdateWindowHeading": "Administrer oppdateringer for {0} ({1})", + "SettingsTabHotkeysResScaleUpHotkey": "Øke oppløsning:", + "SettingsTabHotkeysResScaleDownHotkey": "Reduser oppløsning:", + "UserProfilesName": "Navn:", + "UserProfilesUserId": "Bruker ID:", + "SettingsTabGraphicsBackend": "Grafikk Backend", + "SettingsTabGraphicsBackendTooltip": "Velg grafikkbackend som skal brukes i emulatoren.\n\nVulkan er generelt bedre for alle moderne grafikkort, så lenge driverne er oppdatert. Vulkan har også en raskere sammenstilling av Shader (mindre hakkete) på alle GPU-leverandører.\n\nOpenGL kan oppnå bedre resultater for eldre Nvidia GPU-er, på eldre AMD GPU-er på Linux, eller på GPU-er med lavere VRAM, selv om skyggekompileringsutløser vil være større.\n\nSett til Vulkan hvis du er usikker. Sett til OpenGL hvis ikke GPU-en støtter Vulkan selv med de nyeste grafikkdriverne.", + "SettingsEnableTextureRecompression": "Aktiver teksturkomprimering", + "SettingsEnableTextureRecompressionTooltip": "Kompresser ASTC-teksturer for å redusere VRAM-bruk.\n\nSpill som bruker dette teksturformatet, inkluderer Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder and The Legend of Zelda: Tears of the Kingdom.\n\nGrafikkkort med 4GiB VRAM eller mindre, vil sannsynligvis krasje på et tidspunkt når spillene kjører.\n\nAktiver bare hvis du går tom for VRAM på nevnte spill. La AV om du er usikker.", + "SettingsTabGraphicsPreferredGpu": "Foretrukket GPU", + "SettingsTabGraphicsPreferredGpuTooltip": "Velg grafikkkortet som skal brukes sammen med Vulkan grafikkbackenden\n\nPåvirker ikke GPU-er som OpenGL skal bruke.\n\nSett til GPU-merket som \"dGPU\" hvis usikker. Hvis det ikke det er en, la være uberørt.", + "SettingsAppRequiredRestartMessage": "Ryujinx Omstart nødvendig", + "SettingsGpuBackendRestartMessage": "Grafikk Backend eller GPU-innstillinger er endret. Dette krever en omstart for å aktiveres", + "SettingsGpuBackendRestartSubMessage": "Vil du starte på nytt nå?", + "RyujinxUpdaterMessage": "Ønsker du å oppdatere Ryujinx til den nyeste versjonen?", + "SettingsTabHotkeysVolumeUpHotkey": "Øk Volum:", + "SettingsTabHotkeysVolumeDownHotkey": "Reduser Volum:", + "SettingsEnableMacroHLE": "Aktiver Makro HLE", + "SettingsEnableMacroHLETooltip": "High-level emulering av GPU makrokode.\n\nForbedrer ytelse, men kan forårsake grafiske glitches i noen spill.\n\nForlat PÅ hvis usikker.", + "SettingsEnableColorSpacePassthrough": "Fargeromsgjennomgang", + "SettingsEnableColorSpacePassthroughTooltip": "Dirigerer Vulkan backenden til å gå gjennom farge informasjonen uten og spesifisere en fargeromsgjennomgang. For brukere med en bred spillvisning kan dette resultere i mer vibrerende farger og få riktig farge.", + "VolumeShort": "Vol", + "UserProfilesManageSaves": "Administrer lagring", + "DeleteUserSave": "Vil du slette bruker data for dette spillet?", + "IrreversibleActionNote": "Denne handlingen er ikke reverserbar.", + "SaveManagerHeading": "Administrer lagring for {0} ({1})", + "SaveManagerTitle": "Lagre behandler", + "Name": "Navn", + "Size": "Størrelse", + "Search": "Søk", + "UserProfilesRecoverLostAccounts": "Gjenopprett tapte kontoer", + "Recover": "Gjenopprett", + "UserProfilesRecoverHeading": "Lagring ble funnet for følgende kontoer", + "UserProfilesRecoverEmptyList": "Ingen profiler å gjenopprette", + "GraphicsAATooltip": "Aktiverer anti-aliasing til spill render.\n\nFXAA vil gjøre det meste av bildet, mens SMAA vil forsøke å finne berørte kanter og glatte dem ut.\n\nAnbefales ikke til bruk i forbindelse med FSR-skaleringsfilteret.\n\nDette valget kan endres mens et spill kjører ved å klikke \"Apply\" nedenfor; du kan bare flytte innstillingsvinduet til du finner det foretrukne utseendet til et spill.\n\nForlat på NONE hvis usikker.", + "GraphicsAALabel": "Kantutjevning:", + "GraphicsScalingFilterLabel": "Skaleringsfilter:", + "GraphicsScalingFilterTooltip": "Velg det skaleringsfilteret som skal brukes når du bruker oppløsningsskalaen.\n\nBilinear fungerer godt for 3D-spill og er et trygt standardalternativ.\n\nNærmeste anbefales for pixel kunst-spill.\n\nFSR 1.0 er bare et skarpere filter, ikke anbefalt for bruk med FXAA eller SMAA.\n\nOmrådeskalering anbefales når nedskalering er større enn utgangsvinduet. Den kan brukes til å oppnå en superprøvetaket anti-aliasingseffekt når en nedskalerer med mer enn 2x.\n\nDette valget kan endres mens et spill kjører ved å klikke \"Apply\" nedenfor; du kan bare flytte innstillingsvinduet til du finner det foretrukne utseendet til et spill.\n\nLa være på BILINEAR hvis usikker.", + "GraphicsScalingFilterBilinear": "Bilinear", + "GraphicsScalingFilterNearest": "Nærmeste", + "GraphicsScalingFilterFsr": "FSR", + "GraphicsScalingFilterArea": "Område", + "GraphicsScalingFilterLevelLabel": "Nivå", + "GraphicsScalingFilterLevelTooltip": "Definer FSR 1,0 skarpere nivå. Høyere er skarpere.", + "SmaaLow": "SMAA lav", + "SmaaMedium": "SMAA Middels", + "SmaaHigh": "SMAA høy", + "SmaaUltra": "SMAA Ultra", + "UserEditorTitle": "Rediger bruker", + "UserEditorTitleCreate": "Opprett bruker", + "SettingsTabNetworkInterface": "Nettverksgrensesnitt", + "NetworkInterfaceTooltip": "Nettverksgrensesnittets grensesnitt brukt for LAN/LDN funksjoner.\n\ni konjuksjon med en VPN eller XLink Kai og ett spill med LAN støtte, kan bli brukt til og spoofe ett \"samme-nettverk\" tilkobling over nettet.\n\nLa være på DEFAULT om usikker.", + "NetworkInterfaceDefault": "Standard", + "PackagingShaders": "Pakker Shaders", + "AboutChangelogButton": "Vis endringslogg på GitHub", + "AboutChangelogButtonTooltipMessage": "Klikk for å åpne endringsloggen for denne versjonen i din nettleser.", + "SettingsTabNetworkMultiplayer": "Flerspiller", + "MultiplayerMode": "Modus:", + "MultiplayerModeTooltip": "Endre LDN flerspillermodus.\n\nLdnMitm vil endre lokal trådløst/lokal spillfunksjonalitet i spill som skal fungere som om den var LAN, noe som tillater lokal, samme nettverk forbindelser med andre Ryujinx instanser og hacket Nintendo Switch konsoller som har installert ldn_mitm-modulen.\n\nFlerspiller krever at alle spillerne er på samme versjon (dvs. Super Smash Bros. Ultimat v13.0.1 kan ikke koble til v13.0.0).\n\nForlat DEAKTIVERT hvis usikker.", + "MultiplayerModeDisabled": "Deaktivert", + "MultiplayerModeLdnMitm": "ldn_mitm" +} diff --git a/src/Ryujinx/Assets/Locales/pl_PL.json b/src/Ryujinx/Assets/Locales/pl_PL.json index fa88bab5e..3f7c2c994 100644 --- a/src/Ryujinx/Assets/Locales/pl_PL.json +++ b/src/Ryujinx/Assets/Locales/pl_PL.json @@ -1,6 +1,7 @@ { "Language": "Polski", "MenuBarFileOpenApplet": "Otwórz Aplet", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Otwórz aplet Mii Editor w trybie indywidualnym", "SettingsTabInputDirectMouseAccess": "Bezpośredni dostęp do myszy", "SettingsTabSystemMemoryManagerMode": "Tryb menedżera pamięci:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "Zainstaluj oprogramowanie", "MenuBarFileToolsInstallFirmwareFromFile": "Zainstaluj oprogramowanie z XCI lub ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Zainstaluj oprogramowanie z katalogu", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Zarządzaj rodzajami plików", "MenuBarToolsInstallFileTypes": "Typy plików instalacyjnych", "MenuBarToolsUninstallFileTypes": "Typy plików dezinstalacyjnych", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_View", "MenuBarViewWindow": "Window Size", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Pomoc", "MenuBarHelpCheckForUpdates": "Sprawdź aktualizacje", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "O programie", "MenuSearch": "Wyszukaj...", "GameListHeaderFavorite": "Ulubione", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "Otwiera katalog zawierający mody dla danej aplikacji", "GameListContextMenuOpenSdModsDirectory": "Otwórz katalog modów Atmosphere", "GameListContextMenuOpenSdModsDirectoryToolTip": "Otwiera alternatywny katalog Atmosphere na karcie SD, który zawiera mody danej aplikacji. Przydatne dla modów przygotowanych pod prawdziwy sprzęt.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} Załadowane gry", "StatusBarSystemVersion": "Wersja systemu: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "Wykryto niski limit dla przypisań pamięci", "LinuxVmMaxMapCountDialogTextPrimary": "Czy chcesz zwiększyć wartość vm.max_map_count do {0}", "LinuxVmMaxMapCountDialogTextSecondary": "Niektóre gry mogą próbować przypisać sobie więcej pamięci niż obecnie, jest to dozwolone. Ryujinx ulegnie awarii, gdy limit zostanie przekroczony.", @@ -400,6 +414,8 @@ "InputDialogTitle": "Okno Dialogowe Wprowadzania", "InputDialogOk": "OK", "InputDialogCancel": "Anuluj", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "Wybierz nazwę profilu", "InputDialogAddNewProfileHeader": "Wprowadź nazwę profilu", "InputDialogAddNewProfileSubtext": "(Maksymalna długość: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Wypakowywanie Aktualizacji...", "DialogUpdaterRenamingMessage": "Zmiana Nazwy Aktualizacji...", "DialogUpdaterAddingFilesMessage": "Dodawanie Nowej Aktualizacji...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Aktualizacja Zakończona!", "DialogUpdaterRestartMessage": "Czy chcesz teraz zrestartować Ryujinx?", "DialogUpdaterNoInternetMessage": "Nie masz połączenia z Internetem!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "Pomyślnie odinstalowano typy plików!", "DialogUninstallFileTypesErrorMessage": "Nie udało się odinstalować typów plików.", "DialogOpenSettingsWindowLabel": "Otwórz Okno Ustawień", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "Aplet Kontrolera", "DialogMessageDialogErrorExceptionMessage": "Błąd wyświetlania okna Dialogowego Wiadomości: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Błąd wyświetlania Klawiatury Oprogramowania: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nCzy chcesz kontynuować?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Instalowanie firmware'u...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Wersja systemu {0} została pomyślnie zainstalowana.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Nie będzie innych profili do otwarcia, jeśli wybrany profil zostanie usunięty", "DialogUserProfileDeletionConfirmMessage": "Czy chcesz usunąć wybrany profil", "DialogUserProfileUnsavedChangesTitle": "Uwaga - Niezapisane zmiany", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "Kliknij, aby otworzyć stronę Ryujinx w domyślnej przeglądarce.", "AboutDisclaimerMessage": "Ryujinx nie jest w żaden sposób powiązany z Nintendo™,\nani z żadnym z jej partnerów.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) jest używane\nw naszej emulacji Amiibo.", - "AboutPatreonUrlTooltipMessage": "Kliknij, aby otworzyć stronę Patreon Ryujinx w domyślnej przeglądarce.", "AboutGithubUrlTooltipMessage": "Kliknij, aby otworzyć stronę GitHub Ryujinx w domyślnej przeglądarce.", "AboutDiscordUrlTooltipMessage": "Kliknij, aby otworzyć zaproszenie na serwer Discord Ryujinx w domyślnej przeglądarce.", - "AboutTwitterUrlTooltipMessage": "Kliknij, aby otworzyć stronę Twitter Ryujinx w domyślnej przeglądarce.", "AboutRyujinxAboutTitle": "O Aplikacji:", - "AboutRyujinxAboutContent": "Ryujinx to emulator Nintendo Switch™.\nWspieraj nas na Patreonie.\nOtrzymuj najnowsze wiadomości na naszym Twitterze lub Discordzie.\nDeweloperzy zainteresowani współpracą mogą dowiedzieć się więcej na naszym GitHubie lub Discordzie.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Utrzymywany Przez:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Kliknij, aby otworzyć stronę Współtwórcy w domyślnej przeglądarce.", - "AboutRyujinxSupprtersTitle": "Wspierani na Patreonie Przez:", "AmiiboSeriesLabel": "Seria Amiibo", "AmiiboCharacterLabel": "Postać", "AmiiboScanButtonLabel": "Zeskanuj", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "Wersja {0} - {1}", "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - Info", "RyujinxConfirm": "Ryujinx - Potwierdzenie", "FileDialogAllTypes": "Wszystkie typy", "Never": "Nigdy", "SwkbdMinCharacters": "Musi mieć co najmniej {0} znaków", "SwkbdMinRangeCharacters": "Musi mieć długość od {0}-{1} znaków", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Klawiatura Oprogramowania", "SoftwareKeyboardModeNumeric": "Może składać się jedynie z 0-9 lub '.'", "SoftwareKeyboardModeAlphabet": "Nie może zawierać znaków CJK", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "Dodawanie Nowych Plików...", "UpdaterExtracting": "Wypakowywanie Aktualizacji...", "UpdaterDownloading": "Pobieranie Aktualizacji...", - "Game": "Gra", "Docked": "Zadokowany", "Handheld": "Przenośny", "ConnectionError": "Błąd Połączenia.", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "Wybierz pliki DLC", "SelectUpdateDialogTitle": "Wybierz pliki aktualizacji", "SelectModDialogTitle": "Wybierz katalog modów", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "Menedżer Profili Użytkowników", "CheatWindowTitle": "Menedżer Kodów", "DlcWindowTitle": "Menedżer Zawartości do Pobrania", "ModWindowTitle": "Zarządzaj modami dla {0} ({1})", "UpdateWindowTitle": "Menedżer Aktualizacji Tytułu", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", @@ -735,7 +792,7 @@ "CheatWindowHeading": "Kody Dostępne dla {0} [{1}]", "BuildId": "Identyfikator wersji:", "DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.", - "DlcWindowHeading": "{0} Zawartości do Pobrania dostępna dla {1} ({2})", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "{0} Mod(y/ów)", "UserProfilesEditProfile": "Edytuj Zaznaczone", + "Continue": "Continue", "Cancel": "Anuluj", "Save": "Zapisz", "Discard": "Odrzuć", @@ -810,5 +868,17 @@ "MultiplayerMode": "Tryb:", "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", "MultiplayerModeDisabled": "Wyłączone", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/pt_BR.json b/src/Ryujinx/Assets/Locales/pt_BR.json index 5b7a21494..a62ae31c5 100644 --- a/src/Ryujinx/Assets/Locales/pt_BR.json +++ b/src/Ryujinx/Assets/Locales/pt_BR.json @@ -1,6 +1,7 @@ { "Language": "Português (BR)", "MenuBarFileOpenApplet": "Abrir Applet", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abrir editor Mii em modo avulso", "SettingsTabInputDirectMouseAccess": "Acesso direto ao mouse", "SettingsTabSystemMemoryManagerMode": "Modo de gerenciamento de memória:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "_Instalar firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Instalar firmware a partir de um arquivo ZIP/XCI", "MenuBarFileToolsInstallFirmwareFromDirectory": "Instalar firmware a partir de um diretório", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Gerenciar tipos de arquivo", "MenuBarToolsInstallFileTypes": "Instalar tipos de arquivo", "MenuBarToolsUninstallFileTypes": "Desinstalar tipos de arquivos", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_View", "MenuBarViewWindow": "Window Size", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Ajuda", "MenuBarHelpCheckForUpdates": "_Verificar se há atualizações", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "_Sobre", "MenuSearch": "Buscar...", "GameListHeaderFavorite": "Favorito", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "Abre a pasta que contém os mods da aplicação ", "GameListContextMenuOpenSdModsDirectory": "Abrir diretório de mods Atmosphere", "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} jogos carregados", "StatusBarSystemVersion": "Versão do firmware: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "Limite baixo para mapeamentos de memória detectado", "LinuxVmMaxMapCountDialogTextPrimary": "Você gostaria de aumentar o valor de vm.max_map_count para {0}", "LinuxVmMaxMapCountDialogTextSecondary": "Alguns jogos podem tentar criar mais mapeamentos de memória do que o atualmente permitido. Ryujinx irá falhar assim que este limite for excedido.", @@ -400,6 +414,8 @@ "InputDialogTitle": "Diálogo de texto", "InputDialogOk": "OK", "InputDialogCancel": "Cancelar", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "Escolha o nome de perfil", "InputDialogAddNewProfileHeader": "Escreva o nome do perfil", "InputDialogAddNewProfileSubtext": "(Máximo de caracteres: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Extraindo atualização...", "DialogUpdaterRenamingMessage": "Renomeando atualização...", "DialogUpdaterAddingFilesMessage": "Adicionando nova atualização...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Atualização concluída!", "DialogUpdaterRestartMessage": "Deseja reiniciar o Ryujinx agora?", "DialogUpdaterNoInternetMessage": "Você não está conectado à Internet!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "Tipos de arquivo desinstalados com sucesso!", "DialogUninstallFileTypesErrorMessage": "Falha ao desinstalar tipos de arquivo.", "DialogOpenSettingsWindowLabel": "Abrir janela de configurações", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "Applet de controle", "DialogMessageDialogErrorExceptionMessage": "Erro ao exibir diálogo de mensagem: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Erro ao exibir teclado virtual: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nDeseja continuar?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Instalando firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Versão do sistema {0} instalada com sucesso.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Não haveria nenhum perfil selecionado se o perfil atual fosse deletado", "DialogUserProfileDeletionConfirmMessage": "Deseja deletar o perfil selecionado", "DialogUserProfileUnsavedChangesTitle": "Alerta - Alterações não salvas", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "Clique para abrir o site do Ryujinx no seu navegador padrão.", "AboutDisclaimerMessage": "Ryujinx não é afiliado com a Nintendo™,\nou qualquer um de seus parceiros, de nenhum modo.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) é usado\nem nossa emulação de Amiibo.", - "AboutPatreonUrlTooltipMessage": "Clique para abrir a página do Patreon do Ryujinx no seu navegador padrão.", "AboutGithubUrlTooltipMessage": "Clique para abrir a página do GitHub do Ryujinx no seu navegador padrão.", "AboutDiscordUrlTooltipMessage": "Clique para abrir um convite ao servidor do Discord do Ryujinx no seu navegador padrão.", - "AboutTwitterUrlTooltipMessage": "Clique para abrir a página do Twitter do Ryujinx no seu navegador padrão.", "AboutRyujinxAboutTitle": "Sobre:", - "AboutRyujinxAboutContent": "Ryujinx é um emulador de Nintendo Switch™.\nPor favor, nos dê apoio no Patreon.\nFique por dentro de todas as novidades no Twitter ou Discord.\nDesenvolvedores com interesse em contribuir podem conseguir mais informações no GitHub ou Discord.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Mantido por:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Clique para abrir a página de contribuidores no seu navegador padrão.", - "AboutRyujinxSupprtersTitle": "Apoiado no Patreon por:", "AmiiboSeriesLabel": "Franquia Amiibo", "AmiiboCharacterLabel": "Personagem", "AmiiboScanButtonLabel": "Escanear", @@ -618,7 +641,6 @@ "LoadApplicationFolderTooltip": "Abre o navegador de pastas para seleção de pasta extraída do Switch compatível a ser carregada", "OpenRyujinxFolderTooltip": "Abre o diretório do sistema de arquivos do Ryujinx", "LoadTitleUpdatesFromFolderTooltip": "Abra o explorador de arquivos para selecionar uma ou mais pastas e carregar atualizações de jogo em massa.", - "OpenRyujinxFolderTooltip": "Abrir diretório do sistema de arquivos do Ryujinx", "OpenRyujinxLogsTooltip": "Abre o diretório onde os logs são salvos", "ExitTooltip": "Sair do Ryujinx", "OpenSettingsTooltip": "Abrir janela de configurações", @@ -671,12 +693,21 @@ "TitleUpdateVersionLabel": "Versão {0}", "TitleBundledUpdateVersionLabel": "Empacotado: Versão {0}", "TitleBundledDlcLabel": "Empacotado:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - Informação", "RyujinxConfirm": "Ryujinx - Confirmação", "FileDialogAllTypes": "Todos os tipos", "Never": "Nunca", "SwkbdMinCharacters": "Deve ter pelo menos {0} caracteres", "SwkbdMinRangeCharacters": "Deve ter entre {0}-{1} caracteres", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Teclado por Software", "SoftwareKeyboardModeNumeric": "Deve ser somente 0-9 ou '.'", "SoftwareKeyboardModeAlphabet": "Apenas devem ser caracteres não CJK.", @@ -690,7 +721,6 @@ "UpdaterAddingFiles": "Adicionando novos arquivos...", "UpdaterExtracting": "Extraíndo atualização...", "UpdaterDownloading": "Baixando atualização...", - "Game": "Jogo", "Docked": "TV", "Handheld": "Portátil", "ConnectionError": "Erro de conexão.", @@ -724,10 +754,36 @@ "SelectUpdateDialogTitle": "Selecionar arquivos de atualização", "SelectModDialogTitle": "Select mod directory", "UserProfileWindowTitle": "Gerenciador de perfis de usuário", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "CheatWindowTitle": "Gerenciador de Cheats", "DlcWindowTitle": "Gerenciador de DLC", "ModWindowTitle": "Gerenciar Mods para {0} ({1})", "UpdateWindowTitle": "Gerenciador de atualizações", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} nova(s) atualização(ões) adicionada(s)", @@ -735,7 +791,7 @@ "CheatWindowHeading": "Cheats disponíveis para {0} [{1}]", "BuildId": "ID da Build:", "DlcWindowBundledContentNotice": "DLCs incorporadas não podem ser removidas, apenas desativadas.", - "DlcWindowHeading": "{0} DLCs disponíveis para {1} ({2})", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} novo(s) conteúdo(s) para download adicionado(s)", "AutoloadDlcAddedMessage": "{0} novo(s) conteúdo(s) para download adicionado(s)", "AutoloadDlcRemovedMessage": "{0} conteúdo(s) para download ausente(s) removido(s)", @@ -743,6 +799,7 @@ "AutoloadUpdateRemovedMessage": "{0} atualização(ões) ausente(s) removida(s)", "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Editar selecionado", + "Continue": "Continue", "Cancel": "Cancelar", "Save": "Salvar", "Discard": "Descartar", @@ -810,5 +867,17 @@ "MultiplayerMode": "Modo:", "MultiplayerModeTooltip": "Alterar o modo multiplayer LDN.\n\nLdnMitm modificará a funcionalidade de jogo sem fio/local nos jogos para funcionar como se fosse LAN, permitindo conexões locais, na mesma rede, com outras instâncias do Ryujinx e consoles Nintendo Switch hackeados que possuem o módulo ldn_mitm instalado.\n\nO multiplayer exige que todos os jogadores estejam na mesma versão do jogo (ex.: Super Smash Bros. Ultimate v13.0.1 não consegue se conectar à v13.0.0).\n\nDeixe DESATIVADO se estiver em dúvida.", "MultiplayerModeDisabled": "Desativado", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/ru_RU.json b/src/Ryujinx/Assets/Locales/ru_RU.json index cd17eb301..65785a28c 100644 --- a/src/Ryujinx/Assets/Locales/ru_RU.json +++ b/src/Ryujinx/Assets/Locales/ru_RU.json @@ -1,6 +1,7 @@ { "Language": "Русский (RU)", "MenuBarFileOpenApplet": "Открыть апплет", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Открывает апплет Mii Editor в автономном режиме", "SettingsTabInputDirectMouseAccess": "Прямой ввод мыши", "SettingsTabSystemMemoryManagerMode": "Режим менеджера памяти:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "Установка прошивки", "MenuBarFileToolsInstallFirmwareFromFile": "Установить прошивку из XCI или ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Установить прошивку из папки", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Управление типами файлов", "MenuBarToolsInstallFileTypes": "Установить типы файлов", "MenuBarToolsUninstallFileTypes": "Удалить типы файлов", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_Вид", "MenuBarViewWindow": "Размер окна", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Помощь", "MenuBarHelpCheckForUpdates": "Проверить наличие обновлений", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "О программе", "MenuSearch": "Поиск...", "GameListHeaderFavorite": "Избранное", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "Открывает папку, содержащую моды для приложений и игр", "GameListContextMenuOpenSdModsDirectory": "Открыть папку с модами Atmosphere", "GameListContextMenuOpenSdModsDirectoryToolTip": "Открывает папку Atmosphere на альтернативной SD-карте, которая содержит моды для приложений и игр. Полезно для модов, сделанных для реальной консоли.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} игр загружено", "StatusBarSystemVersion": "Версия прошивки: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "Обнаружен низкий лимит разметки памяти", "LinuxVmMaxMapCountDialogTextPrimary": "Хотите увеличить значение vm.max_map_count до {0}", "LinuxVmMaxMapCountDialogTextSecondary": "Некоторые игры могут создавать большую разметку памяти, чем разрешено на данный момент по умолчанию. Ryujinx вылетит при превышении этого лимита.", @@ -400,6 +414,8 @@ "InputDialogTitle": "Диалоговое окно ввода", "InputDialogOk": "ОК", "InputDialogCancel": "Отмена", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "Выберите никнейм", "InputDialogAddNewProfileHeader": "Пожалуйста, введите никнейм", "InputDialogAddNewProfileSubtext": "(Максимальная длина: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Извлечение обновления...", "DialogUpdaterRenamingMessage": "Переименование обновления...", "DialogUpdaterAddingFilesMessage": "Добавление нового обновления...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Обновление завершено", "DialogUpdaterRestartMessage": "Перезапустить Ryujinx?", "DialogUpdaterNoInternetMessage": "Вы не подключены к интернету", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "Типы файлов успешно удалены", "DialogUninstallFileTypesErrorMessage": "Не удалось удалить типы файлов.", "DialogOpenSettingsWindowLabel": "Открывает окно параметров", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "Апплет контроллера", "DialogMessageDialogErrorExceptionMessage": "Ошибка отображения сообщения: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Ошибка отображения программной клавиатуры: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nПродолжить?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Установка прошивки...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Прошивка версии {0} успешно установлена.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Если выбранный профиль будет удален, другие профили не будут открываться.", "DialogUserProfileDeletionConfirmMessage": "Удалить выбранный профиль?", "DialogUserProfileUnsavedChangesTitle": "Внимание - Несохраненные изменения", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "Нажмите, чтобы открыть веб-сайт Ryujinx", "AboutDisclaimerMessage": "Ryujinx никоим образом не связан ни с Nintendo™, ни с кем-либо из ее партнеров.", "AboutAmiiboDisclaimerMessage": "Amiibo API (www.amiiboapi.com) используется для эмуляции Amiibo.", - "AboutPatreonUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx на Patreon", "AboutGithubUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx на GitHub", "AboutDiscordUrlTooltipMessage": "Нажмите, чтобы открыть приглашение на сервер Ryujinx в Discord", - "AboutTwitterUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx в X (бывший Twitter)", "AboutRyujinxAboutTitle": "О программе:", - "AboutRyujinxAboutContent": "Ryujinx — это эмулятор Nintendo Switch™.\nПожалуйста, поддержите нас на Patreon.\nЧитайте последние новости в наших X (Twitter) или Discord.\nРазработчики, заинтересованные в участии, могут ознакомиться с проектом на GitHub или в Discord.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Разработка:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Нажмите, чтобы открыть страницу с участниками", - "AboutRyujinxSupprtersTitle": "Поддержка на Patreon:", "AmiiboSeriesLabel": "Серия Amiibo", "AmiiboCharacterLabel": "Персонаж", "AmiiboScanButtonLabel": "Сканировать", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "Version {0} - {1}", "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - Информация", "RyujinxConfirm": "Ryujinx - Подтверждение", "FileDialogAllTypes": "Все типы", "Never": "Никогда", "SwkbdMinCharacters": "Должно быть не менее {0} символов.", "SwkbdMinRangeCharacters": "Должно быть {0}-{1} символов", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Программная клавиатура", "SoftwareKeyboardModeNumeric": "Должно быть в диапазоне 0-9 или '.'", "SoftwareKeyboardModeAlphabet": "Не должно быть CJK-символов", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "Добавление новых файлов...", "UpdaterExtracting": "Извлечение обновления...", "UpdaterDownloading": "Загрузка обновления...", - "Game": "Игра", "Docked": "Стационарный режим", "Handheld": "Портативный режим", "ConnectionError": "Ошибка соединения", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "Выберите файлы DLC", "SelectUpdateDialogTitle": "Выберите файлы обновлений", "SelectModDialogTitle": "Выбрать папку с модами", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "Менеджер учетных записей", "CheatWindowTitle": "Менеджер читов", "DlcWindowTitle": "Управление DLC для {0} ({1})", "ModWindowTitle": "Управление модами для {0} ({1})", "UpdateWindowTitle": "Менеджер обновлений игр", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", @@ -735,7 +792,7 @@ "CheatWindowHeading": "Доступные читы для {0} [{1}]", "BuildId": "ID версии:", "DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.", - "DlcWindowHeading": "{0} DLC", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "Моды для {0} ", "UserProfilesEditProfile": "Изменить выбранные", + "Continue": "Continue", "Cancel": "Отмена", "Save": "Сохранить", "Discard": "Отменить", @@ -810,5 +868,17 @@ "MultiplayerMode": "Режим:", "MultiplayerModeTooltip": "Меняет многопользовательский режим LDN.\n\nLdnMitm модифицирует функциональность локальной беспроводной/игры на одном устройстве в играх, позволяя играть с другими пользователями Ryujinx или взломанными консолями Nintendo Switch с установленным модулем ldn_mitm, находящимися в одной локальной сети друг с другом.\n\nМногопользовательская игра требует наличия у всех игроков одной и той же версии игры (т.е. Super Smash Bros. Ultimate v13.0.1 не может подключиться к v13.0.0).\n\nРекомендуется оставить отключенным.", "MultiplayerModeDisabled": "Отключено", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/th_TH.json b/src/Ryujinx/Assets/Locales/th_TH.json index d32cfb737..4dd4b43e9 100644 --- a/src/Ryujinx/Assets/Locales/th_TH.json +++ b/src/Ryujinx/Assets/Locales/th_TH.json @@ -1,6 +1,7 @@ { "Language": "ภาษาไทย", "MenuBarFileOpenApplet": "เปิด Applet", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "เปิดโปรแกรม Mii Editor Applet", "SettingsTabInputDirectMouseAccess": "เข้าถึงเมาส์ได้โดยตรง", "SettingsTabSystemMemoryManagerMode": "โหมดจัดการหน่วยความจำ:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "ติดตั้งเฟิร์มแวร์", "MenuBarFileToolsInstallFirmwareFromFile": "ติดตั้งเฟิร์มแวร์จาก ไฟล์ XCI หรือ ไฟล์ ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "ติดตั้งเฟิร์มแวร์จากไดเร็กทอรี", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "จัดการประเภทไฟล์", "MenuBarToolsInstallFileTypes": "ติดตั้งประเภทไฟล์", "MenuBarToolsUninstallFileTypes": "ถอนการติดตั้งประเภทไฟล์", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_มุมมอง", "MenuBarViewWindow": "ขนาดหน้าต่าง", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_ช่วยเหลือ", "MenuBarHelpCheckForUpdates": "ตรวจสอบอัปเดต", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "เกี่ยวกับ", "MenuSearch": "กำลังค้นหา...", "GameListHeaderFavorite": "ชื่นชอบ", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "เปิดไดเร็กทอรี่ Mods ของแอปพลิเคชัน", "GameListContextMenuOpenSdModsDirectory": "เปิดไดเร็กทอรี่ Mods Atmosphere", "GameListContextMenuOpenSdModsDirectoryToolTip": "เปิดไดเร็กทอรี่ Atmosphere ของการ์ด SD สำรองซึ่งมี Mods ของแอปพลิเคชัน ซึ่งมีประโยชน์สำหรับ Mods ที่บรรจุมากับฮาร์ดแวร์จริง", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "เกมส์โหลดแล้ว {0}/{1}", "StatusBarSystemVersion": "เวอร์ชั่นของระบบ: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "การตั้งค่าหน่วยความถึงขีดจำกัดต่ำสุดแล้ว", "LinuxVmMaxMapCountDialogTextPrimary": "คุณต้องเพิ่มค่า vm.max_map_count ไปยัง {0}", "LinuxVmMaxMapCountDialogTextSecondary": "บางเกมอาจพยายามใช้งานหน่วยความจำมากกว่าที่ได้รับอนุญาตในปัจจุบัน Ryujinx จะปิดตัวลงเมื่อเกินขีดจำกัดนี้", @@ -400,6 +414,8 @@ "InputDialogTitle": "กล่องโต้ตอบการป้อนข้อมูล", "InputDialogOk": "ตกลง", "InputDialogCancel": "ยกเลิก", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "เลือก ชื่อโปรไฟล์", "InputDialogAddNewProfileHeader": "กรุณาใส่ชื่อโปรไฟล์", "InputDialogAddNewProfileSubtext": "(ความยาวสูงสุด: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "กำลังแตกไฟล์อัปเดต...", "DialogUpdaterRenamingMessage": "กำลังลบไฟล์เก่า...", "DialogUpdaterAddingFilesMessage": "กำลังเพิ่มไฟล์อัปเดตใหม่...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "อัปเดตเสร็จสมบูรณ์แล้ว!", "DialogUpdaterRestartMessage": "คุณต้องการรีสตาร์ท Ryujinx ตอนนี้หรือไม่?", "DialogUpdaterNoInternetMessage": "คุณไม่ได้เชื่อมต่อกับอินเทอร์เน็ต!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "ถอนการติดตั้งตามประเภทของไฟล์สำเร็จแล้ว!", "DialogUninstallFileTypesErrorMessage": "ไม่สามารถถอนการติดตั้งตามประเภทของไฟล์ได้", "DialogOpenSettingsWindowLabel": "เปิดหน้าต่างการตั้งค่า", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "คอนโทรลเลอร์ Applet", "DialogMessageDialogErrorExceptionMessage": "เกิดข้อผิดพลาดในการแสดงกล่องโต้ตอบข้อความ: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "เกิดข้อผิดพลาดในการแสดงซอฟต์แวร์แป้นพิมพ์: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nคุณต้องการดำเนินการต่อหรือไม่?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "กำลังติดตั้งเฟิร์มแวร์...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "ระบบเวอร์ชั่น {0} ติดตั้งเรียบร้อยแล้ว", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "จะไม่มีโปรไฟล์อื่นให้เปิดหากโปรไฟล์ที่เลือกถูกลบ", "DialogUserProfileDeletionConfirmMessage": "คุณต้องการลบโปรไฟล์ที่เลือกหรือไม่?", "DialogUserProfileUnsavedChangesTitle": "คำเตือน - มีการเปลี่ยนแปลงที่ไม่ได้บันทึก", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "คลิกเพื่อเปิดเว็บไซต์ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ", "AboutDisclaimerMessage": "ทางผู้พัฒนาโปรแกรม Ryujinx ไม่มีส่วนเกี่ยวข้องกับทางบริษัท Nintendo™\nหรือพันธมิตรใดๆ ทั้งสิ้น!", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) ถูกใช้\nในการจำลอง อะมิโบ ของเรา", - "AboutPatreonUrlTooltipMessage": "คลิกเพื่อเปิดหน้า Patreon ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ", "AboutGithubUrlTooltipMessage": "คลิกเพื่อเปิดหน้า Github ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ", "AboutDiscordUrlTooltipMessage": "คลิกเพื่อเปิดคำเชิญเข้าสู่เซิร์ฟเวอร์ Discord ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ", - "AboutTwitterUrlTooltipMessage": "คลิกเพื่อเปิดหน้าเพจ Twitter ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ", "AboutRyujinxAboutTitle": "เกี่ยวกับ:", - "AboutRyujinxAboutContent": "Ryujinx เป็นอีมูเลเตอร์สำหรับ Nintendo Switch™\nโปรดสนับสนุนเราบน Patreon\nรับข่าวสารล่าสุดทั้งหมดบน Twitter หรือ Discord ของเรา\nนักพัฒนาที่สนใจจะมีส่วนร่วมสามารถดูข้อมูลเพิ่มเติมได้ที่ GitHub หรือ Discord ของเรา", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "ได้รับการดูแลโดย:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "คลิกเพื่อเปิดหน้าผู้มีส่วนร่วมบนเบราว์เซอร์เริ่มต้นของคุณ", - "AboutRyujinxSupprtersTitle": "ผู้สนับสนุนบน Patreon:", "AmiiboSeriesLabel": "Amiibo Series", "AmiiboCharacterLabel": "ตัวละคร", "AmiiboScanButtonLabel": "สแกนเลย", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "เวอร์ชั่น {0}", "TitleBundledUpdateVersionLabel": "Bundled: เวอร์ชั่น {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx – ข้อมูล", "RyujinxConfirm": "Ryujinx - ยืนยัน", "FileDialogAllTypes": "ทุกประเภท", "Never": "ไม่ต้อง", "SwkbdMinCharacters": "ต้องมีความยาวของตัวอักษรอย่างน้อย {0} ตัว", "SwkbdMinRangeCharacters": "ต้องมีความยาวของตัวอักษร {0}-{1} ตัว", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "ซอฟต์แวร์คีย์บอร์ด", "SoftwareKeyboardModeNumeric": "ต้องเป็น 0-9 หรือ '.' เท่านั้น", "SoftwareKeyboardModeAlphabet": "ต้องเป็นตัวอักษรที่ไม่ใช่ประเภท CJK เท่านั้น", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "กำลังเพิ่มไฟล์ใหม่...", "UpdaterExtracting": "กำลังแยกการอัปเดต...", "UpdaterDownloading": "กำลังดาวน์โหลดอัปเดต...", - "Game": "เกมส์", "Docked": "ด็อก", "Handheld": "แฮนด์เฮลด์", "ConnectionError": "การเชื่อมต่อล้มเหลว", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "เลือกไฟล์ DLC", "SelectUpdateDialogTitle": "เลือกไฟล์อัพเดต", "SelectModDialogTitle": "เลือกไดเรกทอรี Mods", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "จัดการโปรไฟล์ผู้ใช้", "CheatWindowTitle": "จัดการสูตรโกง", "DlcWindowTitle": "จัดการ DLC ที่ดาวน์โหลดได้สำหรับ {0} ({1})", "ModWindowTitle": "จัดการม็อดที่ดาวน์โหลดได้สำหรับ {0} ({1})", "UpdateWindowTitle": "จัดการอัปเดตหัวข้อ", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} อัพเดตที่เพิ่มมาใหม่", @@ -735,7 +792,7 @@ "CheatWindowHeading": "สูตรโกงมีให้สำหรับ {0} [{1}]", "BuildId": "รหัสการสร้าง:", "DlcWindowBundledContentNotice": "แพ็ค DLC ไม่สามารถลบทิ้งได้ สามารถปิดใช้งานได้เท่านั้น", - "DlcWindowHeading": "{0} DLC ที่สามารถดาวน์โหลดได้", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} DLC ใหม่ที่เพิ่มเข้ามา", "AutoloadDlcAddedMessage": "{0} ใหม่ที่เพิ่มเข้ามา", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "{0} ม็อด", "UserProfilesEditProfile": "แก้ไขที่เลือกแล้ว", + "Continue": "Continue", "Cancel": "ยกเลิก", "Save": "บันทึก", "Discard": "ละทิ้ง", @@ -810,5 +868,17 @@ "MultiplayerMode": "โหมด:", "MultiplayerModeTooltip": "เปลี่ยนโหมดผู้เล่นหลายคนของ LDN\n\nLdnMitm จะปรับเปลี่ยนฟังก์ชันการเล่นแบบไร้สาย/ภายใน จะให้เกมทำงานเหมือนกับว่าเป็น LAN ช่วยให้สามารถเชื่อมต่อภายในเครือข่ายเดียวกันกับอินสแตนซ์ Ryujinx อื่น ๆ และคอนโซล Nintendo Switch ที่ถูกแฮ็กซึ่งมีโมดูล ldn_mitm ติดตั้งอยู่\n\nผู้เล่นหลายคนต้องการให้ผู้เล่นทุกคนอยู่ในเกมเวอร์ชันเดียวกัน (เช่น Super Smash Bros. Ultimate v13.0.1 ไม่สามารถเชื่อมต่อกับ v13.0.0)\n\nปล่อยให้ปิดการใช้งานหากไม่แน่ใจ", "MultiplayerModeDisabled": "ปิดใช้งาน", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/tr_TR.json b/src/Ryujinx/Assets/Locales/tr_TR.json index 1ac9a0b6e..81310c4d3 100644 --- a/src/Ryujinx/Assets/Locales/tr_TR.json +++ b/src/Ryujinx/Assets/Locales/tr_TR.json @@ -1,6 +1,7 @@ { "Language": "Türkçe", "MenuBarFileOpenApplet": "Applet'i Aç", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Mii Editör Applet'ini Bağımsız Mod'da Aç", "SettingsTabInputDirectMouseAccess": "Doğrudan Mouse Erişimi", "SettingsTabSystemMemoryManagerMode": "Hafıza Yönetim Modu:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "Yazılım Yükle", "MenuBarFileToolsInstallFirmwareFromFile": "XCI veya ZIP'ten Yazılım Yükle", "MenuBarFileToolsInstallFirmwareFromDirectory": "Bir Dizin Üzerinden Yazılım Yükle", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Dosya uzantılarını yönet", "MenuBarToolsInstallFileTypes": "Dosya uzantılarını yükle", "MenuBarToolsUninstallFileTypes": "Dosya uzantılarını kaldır", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "_Görüntüle", "MenuBarViewWindow": "Pencere Boyutu", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "_Yardım", "MenuBarHelpCheckForUpdates": "Güncellemeleri Denetle", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "Hakkında", "MenuSearch": "Ara...", "GameListHeaderFavorite": "Favori", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods", "GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory", "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} Oyun Yüklendi", "StatusBarSystemVersion": "Sistem Sürümü: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "Bellek Haritaları İçin Düşük Limit Tespit Edildi ", "LinuxVmMaxMapCountDialogTextPrimary": "vm.max_map_count değerini {0} sayısına yükseltmek ister misiniz", "LinuxVmMaxMapCountDialogTextSecondary": "Bazı oyunlar şu an izin verilen bellek haritası limitinden daha fazlasını yaratmaya çalışabilir. Ryujinx bu limitin geçildiği takdirde kendini kapatıcaktır.", @@ -400,6 +414,8 @@ "InputDialogTitle": "Giriş Yöntemi Diyaloğu", "InputDialogOk": "Tamam", "InputDialogCancel": "İptal", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "Profil İsmini Seç", "InputDialogAddNewProfileHeader": "Lütfen Bir Profil İsmi Girin", "InputDialogAddNewProfileSubtext": "(Maksimum Uzunluk: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "Güncelleme Ayıklanıyor...", "DialogUpdaterRenamingMessage": "Güncelleme Yeniden Adlandırılıyor...", "DialogUpdaterAddingFilesMessage": "Yeni Güncelleme Ekleniyor...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "Güncelleme Tamamlandı!", "DialogUpdaterRestartMessage": "Ryujinx'i şimdi yeniden başlatmak istiyor musunuz?", "DialogUpdaterNoInternetMessage": "İnternete bağlı değilsiniz!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "Dosya uzantıları başarıyla kaldırıldı!", "DialogUninstallFileTypesErrorMessage": "Dosya uzantıları kaldırma işlemi başarısız oldu.", "DialogOpenSettingsWindowLabel": "Seçenekler Penceresini Aç", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "Kumanda Applet'i", "DialogMessageDialogErrorExceptionMessage": "Mesaj diyaloğu gösterilirken hata: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Mesaj diyaloğu gösterilirken hata: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nDevam etmek istiyor musunuz?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Firmware yükleniyor...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Sistem sürümü {0} başarıyla yüklendi.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Seçilen profil silinirse kullanılabilen başka profil kalmayacak", "DialogUserProfileDeletionConfirmMessage": "Seçilen profili silmek istiyor musunuz", "DialogUserProfileUnsavedChangesTitle": "Uyarı - Kaydedilmemiş Değişiklikler", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "Ryujinx'in websitesini varsayılan tarayıcınızda açmak için tıklayın.", "AboutDisclaimerMessage": "Ryujinx, Nintendo™ veya ortaklarıyla herhangi bir şekilde bağlantılı değildir.", "AboutAmiiboDisclaimerMessage": "Amiibo emülasyonumuzda \nAmiiboAPI (www.amiiboapi.com) kullanılmaktadır.", - "AboutPatreonUrlTooltipMessage": "Ryujinx'in Patreon sayfasını varsayılan tarayıcınızda açmak için tıklayın.", "AboutGithubUrlTooltipMessage": "Ryujinx'in GitHub sayfasını varsayılan tarayıcınızda açmak için tıklayın.", "AboutDiscordUrlTooltipMessage": "Varsayılan tarayıcınızda Ryujinx'in Discord'una bir davet açmak için tıklayın.", - "AboutTwitterUrlTooltipMessage": "Ryujinx'in Twitter sayfasını varsayılan tarayıcınızda açmak için tıklayın.", "AboutRyujinxAboutTitle": "Hakkında:", - "AboutRyujinxAboutContent": "Ryujinx bir Nintendo Switch™ emülatörüdür.\nLütfen bizi Patreon'da destekleyin.\nEn son haberleri Twitter veya Discord'umuzdan alın.\nKatkıda bulunmak isteyen geliştiriciler GitHub veya Discord üzerinden daha fazla bilgi edinebilir.", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "Geliştiriciler:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "Katkıda bulunanlar sayfasını varsayılan tarayıcınızda açmak için tıklayın.", - "AboutRyujinxSupprtersTitle": "Patreon Destekleyicileri:", "AmiiboSeriesLabel": "Amiibo Serisi", "AmiiboCharacterLabel": "Karakter", "AmiiboScanButtonLabel": "Tarat", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "Sürüm {0} - {1}", "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledDlcLabel": "Bundled:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - Bilgi", "RyujinxConfirm": "Ryujinx - Doğrulama", "FileDialogAllTypes": "Tüm türler", "Never": "Hiçbir Zaman", "SwkbdMinCharacters": "En az {0} karakter uzunluğunda olmalı", "SwkbdMinRangeCharacters": "{0}-{1} karakter uzunluğunda olmalı", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "Yazılım Klavyesi", "SoftwareKeyboardModeNumeric": "Sadece 0-9 veya '.' olabilir", "SoftwareKeyboardModeAlphabet": "Sadece CJK-characters olmayan karakterler olabilir", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "Yeni Dosyalar Ekleniyor...", "UpdaterExtracting": "Güncelleme Ayrıştırılıyor...", "UpdaterDownloading": "Güncelleme İndiriliyor...", - "Game": "Oyun", "Docked": "Docked", "Handheld": "El tipi", "ConnectionError": "Bağlantı Hatası.", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "DLC dosyalarını seç", "SelectUpdateDialogTitle": "Güncelleme dosyalarını seç", "SelectModDialogTitle": "Mod Dizinini Seç", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "Kullanıcı Profillerini Yönet", "CheatWindowTitle": "Oyun Hilelerini Yönet", "DlcWindowTitle": "Oyun DLC'lerini Yönet", "ModWindowTitle": "Manage Mods for {0} ({1})", "UpdateWindowTitle": "Oyun Güncellemelerini Yönet", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", @@ -735,7 +792,7 @@ "CheatWindowHeading": "{0} için Hile mevcut [{1}]", "BuildId": "BuildId:", "DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.", - "DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", "ModWindowHeading": "{0} Mod(lar)", "UserProfilesEditProfile": "Seçiliyi Düzenle", + "Continue": "Continue", "Cancel": "İptal", "Save": "Kaydet", "Discard": "Iskarta", @@ -810,5 +868,17 @@ "MultiplayerMode": "Mod:", "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", "MultiplayerModeDisabled": "Devre Dışı", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/uk_UA.json b/src/Ryujinx/Assets/Locales/uk_UA.json index 0e22263b6..4bad27176 100644 --- a/src/Ryujinx/Assets/Locales/uk_UA.json +++ b/src/Ryujinx/Assets/Locales/uk_UA.json @@ -1,814 +1,897 @@ -{ - "Language": "Українська", - "MenuBarFileOpenApplet": "Відкрити аплет", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Відкрити аплет Mii Editor в автономному режимі", - "SettingsTabInputDirectMouseAccess": "Прямий доступ мишею", - "SettingsTabSystemMemoryManagerMode": "Режим диспетчера пам’яті:", - "SettingsTabSystemMemoryManagerModeSoftware": "Програмне забезпечення", - "SettingsTabSystemMemoryManagerModeHost": "Хост (швидко)", - "SettingsTabSystemMemoryManagerModeHostUnchecked": "Неперевірений хост (найшвидший, небезпечний)", - "SettingsTabSystemUseHypervisor": "Використовувати гіпервізор", - "MenuBarFile": "_Файл", - "MenuBarFileOpenFromFile": "_Завантажити програму з файлу", - "MenuBarFileOpenFromFileError": "No applications found in selected file.", - "MenuBarFileOpenUnpacked": "Завантажити _розпаковану гру", - "MenuBarFileLoadDlcFromFolder": "Load DLC From Folder", - "MenuBarFileLoadTitleUpdatesFromFolder": "Load Title Updates From Folder", - "MenuBarFileOpenEmuFolder": "Відкрити теку Ryujinx", - "MenuBarFileOpenLogsFolder": "Відкрити теку журналів змін", - "MenuBarFileExit": "_Вихід", - "MenuBarOptions": "_Параметри", - "MenuBarOptionsToggleFullscreen": "На весь екран", - "MenuBarOptionsStartGamesInFullscreen": "Запускати ігри на весь екран", - "MenuBarOptionsStopEmulation": "Зупинити емуляцію", - "MenuBarOptionsSettings": "_Налаштування", - "MenuBarOptionsManageUserProfiles": "_Керувати профілями користувачів", - "MenuBarActions": "_Дії", - "MenuBarOptionsSimulateWakeUpMessage": "Симулювати повідомлення про пробудження", - "MenuBarActionsScanAmiibo": "Сканувати Amiibo", - "MenuBarTools": "_Інструменти", - "MenuBarToolsInstallFirmware": "Установити прошивку", - "MenuBarFileToolsInstallFirmwareFromFile": "Установити прошивку з XCI або ZIP", - "MenuBarFileToolsInstallFirmwareFromDirectory": "Установити прошивку з теки", - "MenuBarToolsManageFileTypes": "Керувати типами файлів", - "MenuBarToolsInstallFileTypes": "Установити типи файлів", - "MenuBarToolsUninstallFileTypes": "Видалити типи файлів", - "MenuBarView": "_View", - "MenuBarViewWindow": "Window Size", - "MenuBarViewWindow720": "720p", - "MenuBarViewWindow1080": "1080p", - "MenuBarHelp": "_Допомога", - "MenuBarHelpCheckForUpdates": "Перевірити оновлення", - "MenuBarHelpAbout": "Про застосунок", - "MenuSearch": "Пошук...", - "GameListHeaderFavorite": "Обране", - "GameListHeaderIcon": "Значок", - "GameListHeaderApplication": "Назва", - "GameListHeaderDeveloper": "Розробник", - "GameListHeaderVersion": "Версія", - "GameListHeaderTimePlayed": "Зіграно часу", - "GameListHeaderLastPlayed": "Востаннє зіграно", - "GameListHeaderFileExtension": "Розширення файлу", - "GameListHeaderFileSize": "Розмір файлу", - "GameListHeaderPath": "Шлях", - "GameListContextMenuOpenUserSaveDirectory": "Відкрити теку збереження користувача", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "Відкриває каталог, який містить збереження користувача програми", - "GameListContextMenuOpenDeviceSaveDirectory": "Відкрити каталог пристроїв користувача", - "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Відкриває каталог, який містить збереження пристрою програми", - "GameListContextMenuOpenBcatSaveDirectory": "Відкрити каталог користувача BCAT", - "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Відкриває каталог, який містить BCAT-збереження програми", - "GameListContextMenuManageTitleUpdates": "Керування оновленнями заголовків", - "GameListContextMenuManageTitleUpdatesToolTip": "Відкриває вікно керування оновленням заголовка", - "GameListContextMenuManageDlc": "Керування DLC", - "GameListContextMenuManageDlcToolTip": "Відкриває вікно керування DLC", - "GameListContextMenuCacheManagement": "Керування кешем", - "GameListContextMenuCacheManagementPurgePptc": "Очистити кеш PPTC", - "GameListContextMenuCacheManagementPurgePptcToolTip": "Видаляє кеш PPTC програми", - "GameListContextMenuCacheManagementPurgeShaderCache": "Очистити кеш шейдерів", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Видаляє кеш шейдерів програми", - "GameListContextMenuCacheManagementOpenPptcDirectory": "Відкрити каталог PPTC", - "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Відкриває каталог, який містить кеш PPTC програми", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Відкрити каталог кешу шейдерів", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Відкриває каталог, який містить кеш шейдерів програми", - "GameListContextMenuExtractData": "Видобути дані", - "GameListContextMenuExtractDataExeFS": "ExeFS", - "GameListContextMenuExtractDataExeFSToolTip": "Видобуває розділ ExeFS із поточної конфігурації програми (включаючи оновлення)", - "GameListContextMenuExtractDataRomFS": "RomFS", - "GameListContextMenuExtractDataRomFSToolTip": "Видобуває розділ RomFS із поточної конфігурації програми (включаючи оновлення)", - "GameListContextMenuExtractDataLogo": "Логотип", - "GameListContextMenuExtractDataLogoToolTip": "Видобуває розділ логотипу з поточної конфігурації програми (включаючи оновлення)", - "GameListContextMenuCreateShortcut": "Створити ярлик застосунку", - "GameListContextMenuCreateShortcutToolTip": "Створити ярлик на робочому столі, який запускає вибраний застосунок", - "GameListContextMenuCreateShortcutToolTipMacOS": "Створити ярлик у каталозі macOS програм, що запускає обраний Додаток", - "GameListContextMenuOpenModsDirectory": "Відкрити теку з модами", - "GameListContextMenuOpenModsDirectoryToolTip": "Відкриває каталог, який містить модифікації Додатків", - "GameListContextMenuOpenSdModsDirectory": "Відкрити каталог модифікацій Atmosphere", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Відкриває альтернативний каталог SD-карти Atmosphere, що містить модифікації Додатків. Корисно для модифікацій, зроблених для реального обладнання.", - "StatusBarGamesLoaded": "{0}/{1} ігор завантажено", - "StatusBarSystemVersion": "Версія системи: {0}", - "LinuxVmMaxMapCountDialogTitle": "Виявлено низьку межу для відображення памʼяті", - "LinuxVmMaxMapCountDialogTextPrimary": "Бажаєте збільшити значення vm.max_map_count на {0}", - "LinuxVmMaxMapCountDialogTextSecondary": "Деякі ігри можуть спробувати створити більше відображень памʼяті, ніж дозволено наразі. Ryujinx завершить роботу, щойно цей ліміт буде перевищено.", - "LinuxVmMaxMapCountDialogButtonUntilRestart": "Так, до наст. перезапуску", - "LinuxVmMaxMapCountDialogButtonPersistent": "Так, назавжди", - "LinuxVmMaxMapCountWarningTextPrimary": "Максимальна кількість відображення памʼяті менша, ніж рекомендовано.", - "LinuxVmMaxMapCountWarningTextSecondary": "Поточне значення vm.max_map_count ({0}) менше за {1}. Деякі ігри можуть спробувати створити більше відображень пам’яті, ніж дозволено наразі. Ryujinx завершить роботу, щойно цей ліміт буде перевищено.\n\nВи можете збільшити ліміт вручну або встановити pkexec, який дозволяє Ryujinx допомогти з цим.", - "Settings": "Налаштування", - "SettingsTabGeneral": "Інтерфейс користувача", - "SettingsTabGeneralGeneral": "Загальні", - "SettingsTabGeneralEnableDiscordRichPresence": "Увімкнути розширену присутність Discord", - "SettingsTabGeneralCheckUpdatesOnLaunch": "Перевіряти наявність оновлень під час запуску", - "SettingsTabGeneralShowConfirmExitDialog": "Показати діалогове вікно «Підтвердити вихід».", - "SettingsTabGeneralRememberWindowState": "Remember Window Size/Position", - "SettingsTabGeneralShowTitleBar": "Show Title Bar (Requires restart)", - "SettingsTabGeneralHideCursor": "Сховати вказівник:", - "SettingsTabGeneralHideCursorNever": "Ніколи", - "SettingsTabGeneralHideCursorOnIdle": "Сховати у режимі очікування", - "SettingsTabGeneralHideCursorAlways": "Завжди", - "SettingsTabGeneralGameDirectories": "Тека ігор", - "SettingsTabGeneralAutoloadDirectories": "Autoload DLC/Updates Directories", - "SettingsTabGeneralAutoloadNote": "DLC and Updates which refer to missing files will be unloaded automatically", - "SettingsTabGeneralAdd": "Додати", - "SettingsTabGeneralRemove": "Видалити", - "SettingsTabSystem": "Система", - "SettingsTabSystemCore": "Ядро", - "SettingsTabSystemSystemRegion": "Регіон системи:", - "SettingsTabSystemSystemRegionJapan": "Японія", - "SettingsTabSystemSystemRegionUSA": "США", - "SettingsTabSystemSystemRegionEurope": "Європа", - "SettingsTabSystemSystemRegionAustralia": "Австралія", - "SettingsTabSystemSystemRegionChina": "Китай", - "SettingsTabSystemSystemRegionKorea": "Корея", - "SettingsTabSystemSystemRegionTaiwan": "Тайвань", - "SettingsTabSystemSystemLanguage": "Мова системи:", - "SettingsTabSystemSystemLanguageJapanese": "Японська", - "SettingsTabSystemSystemLanguageAmericanEnglish": "Англійська (США)", - "SettingsTabSystemSystemLanguageFrench": "Французька", - "SettingsTabSystemSystemLanguageGerman": "Німецька", - "SettingsTabSystemSystemLanguageItalian": "Італійська", - "SettingsTabSystemSystemLanguageSpanish": "Іспанська", - "SettingsTabSystemSystemLanguageChinese": "Китайська", - "SettingsTabSystemSystemLanguageKorean": "Корейська", - "SettingsTabSystemSystemLanguageDutch": "Нідерландська", - "SettingsTabSystemSystemLanguagePortuguese": "Португальська", - "SettingsTabSystemSystemLanguageRussian": "Російська", - "SettingsTabSystemSystemLanguageTaiwanese": "Тайванська", - "SettingsTabSystemSystemLanguageBritishEnglish": "Англійська (Великобританія)", - "SettingsTabSystemSystemLanguageCanadianFrench": "Французька (Канада)", - "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Іспанська (Латиноамериканська)", - "SettingsTabSystemSystemLanguageSimplifiedChinese": "Спрощена китайська", - "SettingsTabSystemSystemLanguageTraditionalChinese": "Традиційна китайська", - "SettingsTabSystemSystemTimeZone": "Часовий пояс системи:", - "SettingsTabSystemSystemTime": "Час системи:", - "SettingsTabSystemEnableVsync": "Вертикальна синхронізація", - "SettingsTabSystemEnablePptc": "PPTC (профільований постійний кеш перекладу)", - "SettingsTabSystemEnableLowPowerPptc": "Low-power PPTC", - "SettingsTabSystemEnableFsIntegrityChecks": "Перевірка цілісності FS", - "SettingsTabSystemAudioBackend": "Аудіосистема:", - "SettingsTabSystemAudioBackendDummy": "Dummy", - "SettingsTabSystemAudioBackendOpenAL": "OpenAL", - "SettingsTabSystemAudioBackendSoundIO": "SoundIO", - "SettingsTabSystemAudioBackendSDL2": "SDL2", - "SettingsTabSystemHacks": "Хитрощі", - "SettingsTabSystemHacksNote": " (може викликати нестабільність)", - "SettingsTabSystemDramSize": "Використовувати альтернативне розташування пам'яті (розробники)", - "SettingsTabSystemDramSize4GiB": "4GiB", - "SettingsTabSystemDramSize6GiB": "6GiB", - "SettingsTabSystemDramSize8GiB": "8GiB", - "SettingsTabSystemDramSize12GiB": "12GiB", - "SettingsTabSystemIgnoreMissingServices": "Ігнорувати відсутні служби", - "SettingsTabSystemIgnoreApplet": "Ігнорувати Аплет", - "SettingsTabGraphics": "Графіка", - "SettingsTabGraphicsAPI": "Графічний API", - "SettingsTabGraphicsEnableShaderCache": "Увімкнути кеш шейдерів", - "SettingsTabGraphicsAnisotropicFiltering": "Анізотропна фільтрація:", - "SettingsTabGraphicsAnisotropicFilteringAuto": "Авто", - "SettingsTabGraphicsAnisotropicFiltering2x": "2x", - "SettingsTabGraphicsAnisotropicFiltering4x": "4x", - "SettingsTabGraphicsAnisotropicFiltering8x": "8x", - "SettingsTabGraphicsAnisotropicFiltering16x": "16x", - "SettingsTabGraphicsResolutionScale": "Роздільна здатність:", - "SettingsTabGraphicsResolutionScaleCustom": "Користувацька (не рекомендовано)", - "SettingsTabGraphicsResolutionScaleNative": "Стандартний (720p/1080p)", - "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", - "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Не рекомендується)", - "SettingsTabGraphicsAspectRatio": "Співвідношення сторін:", - "SettingsTabGraphicsAspectRatio4x3": "4:3", - "SettingsTabGraphicsAspectRatio16x9": "16:9", - "SettingsTabGraphicsAspectRatio16x10": "16:10", - "SettingsTabGraphicsAspectRatio21x9": "21:9", - "SettingsTabGraphicsAspectRatio32x9": "32:9", - "SettingsTabGraphicsAspectRatioStretch": "Розтягнути до розміру вікна", - "SettingsTabGraphicsDeveloperOptions": "Параметри розробника", - "SettingsTabGraphicsShaderDumpPath": "Шлях скидання графічного шейдера:", - "SettingsTabLogging": "Налагодження", - "SettingsTabLoggingLogging": "Налагодження", - "SettingsTabLoggingEnableLoggingToFile": "Увімкнути налагодження у файл", - "SettingsTabLoggingEnableStubLogs": "Увімкнути журнали заглушки", - "SettingsTabLoggingEnableInfoLogs": "Увімкнути інформаційні журнали", - "SettingsTabLoggingEnableWarningLogs": "Увімкнути журнали попереджень", - "SettingsTabLoggingEnableErrorLogs": "Увімкнути журнали помилок", - "SettingsTabLoggingEnableTraceLogs": "Увімкнути журнали трасування", - "SettingsTabLoggingEnableGuestLogs": "Увімкнути журнали гостей", - "SettingsTabLoggingEnableFsAccessLogs": "Увімкнути журнали доступу Fs", - "SettingsTabLoggingFsGlobalAccessLogMode": "Режим журналу глобального доступу Fs:", - "SettingsTabLoggingDeveloperOptions": "Параметри розробника (УВАГА: знизиться продуктивність)", - "SettingsTabLoggingDeveloperOptionsNote": "УВАГА: Знижує продуктивність", - "SettingsTabLoggingGraphicsBackendLogLevel": "Рівень журналу графічного сервера:", - "SettingsTabLoggingGraphicsBackendLogLevelNone": "Немає", - "SettingsTabLoggingGraphicsBackendLogLevelError": "Помилка", - "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Уповільнення", - "SettingsTabLoggingGraphicsBackendLogLevelAll": "Все", - "SettingsTabLoggingEnableDebugLogs": "Увімкнути журнали налагодження", - "SettingsTabInput": "Введення", - "SettingsTabInputEnableDockedMode": "Режим док-станції", - "SettingsTabInputDirectKeyboardAccess": "Прямий доступ з клавіатури", - "SettingsButtonSave": "Зберегти", - "SettingsButtonClose": "Закрити", - "SettingsButtonOk": "Гаразд", - "SettingsButtonCancel": "Скасувати", - "SettingsButtonApply": "Застосувати", - "ControllerSettingsPlayer": "Гравець", - "ControllerSettingsPlayer1": "Гравець 1", - "ControllerSettingsPlayer2": "Гравець 2", - "ControllerSettingsPlayer3": "Гравець 3", - "ControllerSettingsPlayer4": "Гравець 4", - "ControllerSettingsPlayer5": "Гравець 5", - "ControllerSettingsPlayer6": "Гравець 6", - "ControllerSettingsPlayer7": "Гравець 7", - "ControllerSettingsPlayer8": "Гравець 8", - "ControllerSettingsHandheld": "Портативний", - "ControllerSettingsInputDevice": "Пристрій введення", - "ControllerSettingsRefresh": "Оновити", - "ControllerSettingsDeviceDisabled": "Вимкнено", - "ControllerSettingsControllerType": "Тип контролера", - "ControllerSettingsControllerTypeHandheld": "Портативний", - "ControllerSettingsControllerTypeProController": "Контролер Pro", - "ControllerSettingsControllerTypeJoyConPair": "Обидва JoyCon", - "ControllerSettingsControllerTypeJoyConLeft": "Лівий JoyCon", - "ControllerSettingsControllerTypeJoyConRight": "Правий JoyCon", - "ControllerSettingsProfile": "Профіль", - "ControllerSettingsProfileDefault": "Типовий", - "ControllerSettingsLoad": "Завантажити", - "ControllerSettingsAdd": "Додати", - "ControllerSettingsRemove": "Видалити", - "ControllerSettingsButtons": "Кнопки", - "ControllerSettingsButtonA": "A", - "ControllerSettingsButtonB": "B", - "ControllerSettingsButtonX": "X", - "ControllerSettingsButtonY": "Y", - "ControllerSettingsButtonPlus": "+", - "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "Панель направлення", - "ControllerSettingsDPadUp": "Вгору", - "ControllerSettingsDPadDown": "Вниз", - "ControllerSettingsDPadLeft": "Вліво", - "ControllerSettingsDPadRight": "Вправо", - "ControllerSettingsStickButton": "Кнопка", - "ControllerSettingsStickUp": "Уверх", - "ControllerSettingsStickDown": "Униз", - "ControllerSettingsStickLeft": "Ліворуч", - "ControllerSettingsStickRight": "Праворуч", - "ControllerSettingsStickStick": "Стик", - "ControllerSettingsStickInvertXAxis": "Обернути вісь стику X", - "ControllerSettingsStickInvertYAxis": "Обернути вісь стику Y", - "ControllerSettingsStickDeadzone": "Мертва зона:", - "ControllerSettingsLStick": "Лівий джойстик", - "ControllerSettingsRStick": "Правий джойстик", - "ControllerSettingsTriggersLeft": "Тригери ліворуч", - "ControllerSettingsTriggersRight": "Тригери праворуч", - "ControllerSettingsTriggersButtonsLeft": "Кнопки тригерів ліворуч", - "ControllerSettingsTriggersButtonsRight": "Кнопки тригерів праворуч", - "ControllerSettingsTriggers": "Тригери", - "ControllerSettingsTriggerL": "L", - "ControllerSettingsTriggerR": "R", - "ControllerSettingsTriggerZL": "ZL", - "ControllerSettingsTriggerZR": "ZR", - "ControllerSettingsLeftSL": "SL", - "ControllerSettingsLeftSR": "SR", - "ControllerSettingsRightSL": "SL", - "ControllerSettingsRightSR": "SR", - "ControllerSettingsExtraButtonsLeft": "Кнопки ліворуч", - "ControllerSettingsExtraButtonsRight": "Кнопки праворуч", - "ControllerSettingsMisc": "Різне", - "ControllerSettingsTriggerThreshold": "Поріг спрацьовування:", - "ControllerSettingsMotion": "Рух", - "ControllerSettingsMotionUseCemuhookCompatibleMotion": "Використовувати рух, сумісний з CemuHook", - "ControllerSettingsMotionControllerSlot": "Слот контролера:", - "ControllerSettingsMotionMirrorInput": "Дзеркальний вхід", - "ControllerSettingsMotionRightJoyConSlot": "Правий слот JoyCon:", - "ControllerSettingsMotionServerHost": "Хост сервера:", - "ControllerSettingsMotionGyroSensitivity": "Чутливість гіроскопа:", - "ControllerSettingsMotionGyroDeadzone": "Мертва зона гіроскопа:", - "ControllerSettingsSave": "Зберегти", - "ControllerSettingsClose": "Закрити", - "KeyUnknown": "Unknown", - "KeyShiftLeft": "Shift Left", - "KeyShiftRight": "Shift Right", - "KeyControlLeft": "Ctrl Left", - "KeyMacControlLeft": "⌃ Left", - "KeyControlRight": "Ctrl Right", - "KeyMacControlRight": "⌃ Right", - "KeyAltLeft": "Alt Left", - "KeyMacAltLeft": "⌥ Left", - "KeyAltRight": "Alt Right", - "KeyMacAltRight": "⌥ Right", - "KeyWinLeft": "⊞ Left", - "KeyMacWinLeft": "⌘ Left", - "KeyWinRight": "⊞ Right", - "KeyMacWinRight": "⌘ Right", - "KeyMenu": "Menu", - "KeyUp": "Up", - "KeyDown": "Down", - "KeyLeft": "Left", - "KeyRight": "Right", - "KeyEnter": "Enter", - "KeyEscape": "Escape", - "KeySpace": "Space", - "KeyTab": "Tab", - "KeyBackSpace": "Backspace", - "KeyInsert": "Insert", - "KeyDelete": "Delete", - "KeyPageUp": "Page Up", - "KeyPageDown": "Page Down", - "KeyHome": "Home", - "KeyEnd": "End", - "KeyCapsLock": "Caps Lock", - "KeyScrollLock": "Scroll Lock", - "KeyPrintScreen": "Print Screen", - "KeyPause": "Pause", - "KeyNumLock": "Num Lock", - "KeyClear": "Clear", - "KeyKeypad0": "Keypad 0", - "KeyKeypad1": "Keypad 1", - "KeyKeypad2": "Keypad 2", - "KeyKeypad3": "Keypad 3", - "KeyKeypad4": "Keypad 4", - "KeyKeypad5": "Keypad 5", - "KeyKeypad6": "Keypad 6", - "KeyKeypad7": "Keypad 7", - "KeyKeypad8": "Keypad 8", - "KeyKeypad9": "Keypad 9", - "KeyKeypadDivide": "Keypad Divide", - "KeyKeypadMultiply": "Keypad Multiply", - "KeyKeypadSubtract": "Keypad Subtract", - "KeyKeypadAdd": "Keypad Add", - "KeyKeypadDecimal": "Keypad Decimal", - "KeyKeypadEnter": "Keypad Enter", - "KeyNumber0": "0", - "KeyNumber1": "1", - "KeyNumber2": "2", - "KeyNumber3": "3", - "KeyNumber4": "4", - "KeyNumber5": "5", - "KeyNumber6": "6", - "KeyNumber7": "7", - "KeyNumber8": "8", - "KeyNumber9": "9", - "KeyTilde": "~", - "KeyGrave": "`", - "KeyMinus": "-", - "KeyPlus": "+", - "KeyBracketLeft": "[", - "KeyBracketRight": "]", - "KeySemicolon": ";", - "KeyQuote": "\"", - "KeyComma": ",", - "KeyPeriod": ".", - "KeySlash": "/", - "KeyBackSlash": "\\", - "KeyUnbound": "Unbound", - "GamepadLeftStick": "L Stick Button", - "GamepadRightStick": "R Stick Button", - "GamepadLeftShoulder": "Left Shoulder", - "GamepadRightShoulder": "Right Shoulder", - "GamepadLeftTrigger": "Left Trigger", - "GamepadRightTrigger": "Right Trigger", - "GamepadDpadUp": "Up", - "GamepadDpadDown": "Down", - "GamepadDpadLeft": "Left", - "GamepadDpadRight": "Right", - "GamepadMinus": "-", - "GamepadPlus": "+", - "GamepadGuide": "Guide", - "GamepadMisc1": "Misc", - "GamepadPaddle1": "Paddle 1", - "GamepadPaddle2": "Paddle 2", - "GamepadPaddle3": "Paddle 3", - "GamepadPaddle4": "Paddle 4", - "GamepadTouchpad": "Touchpad", - "GamepadSingleLeftTrigger0": "Left Trigger 0", - "GamepadSingleRightTrigger0": "Right Trigger 0", - "GamepadSingleLeftTrigger1": "Left Trigger 1", - "GamepadSingleRightTrigger1": "Right Trigger 1", - "StickLeft": "Left Stick", - "StickRight": "Right Stick", - "UserProfilesSelectedUserProfile": "Вибраний профіль користувача:", - "UserProfilesSaveProfileName": "Зберегти ім'я профілю", - "UserProfilesChangeProfileImage": "Змінити зображення профілю", - "UserProfilesAvailableUserProfiles": "Доступні профілі користувачів:", - "UserProfilesAddNewProfile": "Створити профіль", - "UserProfilesDelete": "Видалити", - "UserProfilesClose": "Закрити", - "ProfileNameSelectionWatermark": "Оберіть псевдонім", - "ProfileImageSelectionTitle": "Вибір зображення профілю", - "ProfileImageSelectionHeader": "Виберіть зображення профілю", - "ProfileImageSelectionNote": "Ви можете імпортувати власне зображення профілю або вибрати аватар із мікропрограми системи", - "ProfileImageSelectionImportImage": "Імпорт файлу зображення", - "ProfileImageSelectionSelectAvatar": "Виберіть аватар прошивки ", - "InputDialogTitle": "Діалог введення", - "InputDialogOk": "Гаразд", - "InputDialogCancel": "Скасувати", - "InputDialogAddNewProfileTitle": "Виберіть ім'я профілю", - "InputDialogAddNewProfileHeader": "Будь ласка, введіть ім'я профілю", - "InputDialogAddNewProfileSubtext": "(Макс. довжина: {0})", - "AvatarChoose": "Вибрати", - "AvatarSetBackgroundColor": "Встановити колір фону", - "AvatarClose": "Закрити", - "ControllerSettingsLoadProfileToolTip": "Завантажити профіль", - "ControllerSettingsViewProfileToolTip": "View Profile", - "ControllerSettingsAddProfileToolTip": "Додати профіль", - "ControllerSettingsRemoveProfileToolTip": "Видалити профіль", - "ControllerSettingsSaveProfileToolTip": "Зберегти профіль", - "MenuBarFileToolsTakeScreenshot": "Зробити знімок екрана", - "MenuBarFileToolsHideUi": "Сховати інтерфейс", - "GameListContextMenuRunApplication": "Запустити додаток", - "GameListContextMenuToggleFavorite": "Перемкнути вибране", - "GameListContextMenuToggleFavoriteToolTip": "Перемкнути улюблений статус гри", - "SettingsTabGeneralTheme": "Тема:", - "SettingsTabGeneralThemeAuto": "Auto", - "SettingsTabGeneralThemeDark": "Темна", - "SettingsTabGeneralThemeLight": "Світла", - "ControllerSettingsConfigureGeneral": "Налаштування", - "ControllerSettingsRumble": "Вібрація", - "ControllerSettingsRumbleStrongMultiplier": "Множник сильної вібрації", - "ControllerSettingsRumbleWeakMultiplier": "Множник слабкої вібрації", - "DialogMessageSaveNotAvailableMessage": "Немає збережених даних для {0} [{1:x16}]", - "DialogMessageSaveNotAvailableCreateSaveMessage": "Хочете створити дані збереження для цієї гри?", - "DialogConfirmationTitle": "Ryujinx - Підтвердження", - "DialogUpdaterTitle": "Ryujinx - Програма оновлення", - "DialogErrorTitle": "Ryujinx - Помилка", - "DialogWarningTitle": "Ryujinx - Попередження", - "DialogExitTitle": "Ryujinx - Вихід", - "DialogErrorMessage": "У Ryujinx сталася помилка", - "DialogExitMessage": "Ви впевнені, що бажаєте закрити Ryujinx?", - "DialogExitSubMessage": "Усі незбережені дані буде втрачено!", - "DialogMessageCreateSaveErrorMessage": "Під час створення вказаних даних збереження сталася помилка: {0}", - "DialogMessageFindSaveErrorMessage": "Під час пошуку вказаних даних збереження сталася помилка: {0}", - "FolderDialogExtractTitle": "Виберіть папку для видобування", - "DialogNcaExtractionMessage": "Видобування розділу {0} з {1}...", - "DialogNcaExtractionTitle": "Екстрактор розділів NCA", - "DialogNcaExtractionMainNcaNotFoundErrorMessage": "Помилка видобування. Основний NCA не був присутній у вибраному файлі.", - "DialogNcaExtractionCheckLogErrorMessage": "Помилка видобування. Прочитайте файл журналу для отримання додаткової інформації.", - "DialogNcaExtractionSuccessMessage": "Видобування успішно завершено.", - "DialogUpdaterConvertFailedMessage": "Не вдалося конвертувати поточну версію Ryujinx.", - "DialogUpdaterCancelUpdateMessage": "Скасування оновлення!", - "DialogUpdaterAlreadyOnLatestVersionMessage": "Ви вже використовуєте останню версію Ryujinx!", - "DialogUpdaterFailedToGetVersionMessage": "Під час спроби отримати інформацію про випуск із GitHub Release сталася помилка. Це може бути спричинено, якщо новий випуск компілюється GitHub Actions. Повторіть спробу через кілька хвилин.", - "DialogUpdaterConvertFailedGithubMessage": "Не вдалося конвертувати отриману версію Ryujinx із випуску Github.", - "DialogUpdaterDownloadingMessage": "Завантаження оновлення...", - "DialogUpdaterExtractionMessage": "Видобування оновлення...", - "DialogUpdaterRenamingMessage": "Перейменування оновлення...", - "DialogUpdaterAddingFilesMessage": "Додавання нового оновлення...", - "DialogUpdaterCompleteMessage": "Оновлення завершено!", - "DialogUpdaterRestartMessage": "Перезапустити Ryujinx зараз?", - "DialogUpdaterNoInternetMessage": "Ви не підключені до Інтернету!", - "DialogUpdaterNoInternetSubMessage": "Будь ласка, переконайтеся, що у вас є робоче підключення до Інтернету!", - "DialogUpdaterDirtyBuildMessage": "Ви не можете оновити брудну збірку Ryujinx!", - "DialogUpdaterDirtyBuildSubMessage": "Будь ласка, завантажте Ryujinx на https://ryujinx.app/download, якщо ви шукаєте підтримувану версію.", - "DialogRestartRequiredMessage": "Потрібен перезапуск", - "DialogThemeRestartMessage": "Тему збережено. Щоб застосувати тему, потрібен перезапуск.", - "DialogThemeRestartSubMessage": "Ви хочете перезапустити", - "DialogFirmwareInstallEmbeddedMessage": "Бажаєте встановити прошивку, вбудовану в цю гру? (Прошивка {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Встановлену прошивку не знайдено, але Ryujinx вдалося встановити прошивку {0} з наданої гри.\nТепер запуститься емулятор.", - "DialogFirmwareNoFirmwareInstalledMessage": "Прошивка не встановлена", - "DialogFirmwareInstalledMessage": "Встановлено прошивку {0}", - "DialogInstallFileTypesSuccessMessage": "Успішно встановлено типи файлів!", - "DialogInstallFileTypesErrorMessage": "Не вдалося встановити типи файлів.", - "DialogUninstallFileTypesSuccessMessage": "Успішно видалено типи файлів!", - "DialogUninstallFileTypesErrorMessage": "Не вдалося видалити типи файлів.", - "DialogOpenSettingsWindowLabel": "Відкрити вікно налаштувань", - "DialogControllerAppletTitle": "Аплет контролера", - "DialogMessageDialogErrorExceptionMessage": "Помилка показу діалогового вікна повідомлення: {0}", - "DialogSoftwareKeyboardErrorExceptionMessage": "Помилка показу програмної клавіатури: {0}", - "DialogErrorAppletErrorExceptionMessage": "Помилка показу діалогового вікна ErrorApplet: {0}", - "DialogUserErrorDialogMessage": "{0}: {1}", - "DialogUserErrorDialogInfoMessage": "\nДля отримання додаткової інформації про те, як виправити цю помилку, дотримуйтесь нашого посібника з налаштування.", - "DialogUserErrorDialogTitle": "Помилка Ryujinx ({0})", - "DialogAmiiboApiTitle": "Amiibo API", - "DialogAmiiboApiFailFetchMessage": "Під час отримання інформації з API сталася помилка.", - "DialogAmiiboApiConnectErrorMessage": "Неможливо підключитися до сервера Amiibo API. Можливо, служба не працює або вам потрібно перевірити, чи є підключення до Інтернету.", - "DialogProfileInvalidProfileErrorMessage": "Профіль {0} несумісний із поточною системою конфігурації вводу.", - "DialogProfileDefaultProfileOverwriteErrorMessage": "Стандартний профіль не можна перезаписати", - "DialogProfileDeleteProfileTitle": "Видалення профілю", - "DialogProfileDeleteProfileMessage": "Цю дію неможливо скасувати. Ви впевнені, що бажаєте продовжити?", - "DialogWarning": "Увага", - "DialogPPTCDeletionMessage": "Ви збираєтеся видалити кеш PPTC для:\n\n{0}\n\nВи впевнені, що бажаєте продовжити?", - "DialogPPTCDeletionErrorMessage": "Помилка очищення кешу PPTC на {0}: {1}", - "DialogShaderDeletionMessage": "Ви збираєтеся видалити кеш шейдерів для:\n\n{0}\n\nВи впевнені, що бажаєте продовжити?", - "DialogShaderDeletionErrorMessage": "Помилка очищення кешу шейдерів на {0}: {1}", - "DialogRyujinxErrorMessage": "У Ryujinx сталася помилка", - "DialogInvalidTitleIdErrorMessage": "Помилка інтерфейсу: вибрана гра не мала дійсного ідентифікатора назви", - "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Дійсна прошивка системи не знайдена в {0}.", - "DialogFirmwareInstallerFirmwareInstallTitle": "Встановити прошивку {0}", - "DialogFirmwareInstallerFirmwareInstallMessage": "Буде встановлено версію системи {0}.", - "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nЦе замінить поточну версію системи {0}.", - "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nВи хочете продовжити?", - "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Встановлення прошивки...", - "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Версію системи {0} успішно встановлено.", - "DialogUserProfileDeletionWarningMessage": "Якщо вибраний профіль буде видалено, інші профілі не відкриватимуться", - "DialogUserProfileDeletionConfirmMessage": "Ви хочете видалити вибраний профіль", - "DialogUserProfileUnsavedChangesTitle": "Увага — Незбережені зміни", - "DialogUserProfileUnsavedChangesMessage": "Ви зробили зміни у цьому профілю користувача які не було збережено.", - "DialogUserProfileUnsavedChangesSubMessage": "Бажаєте скасувати зміни?", - "DialogControllerSettingsModifiedConfirmMessage": "Поточні налаштування контролера оновлено.", - "DialogControllerSettingsModifiedConfirmSubMessage": "Ви хочете зберегти?", - "DialogLoadFileErrorMessage": "{0}. Файл з помилкою: {1}", - "DialogModAlreadyExistsMessage": "Модифікація вже існує", - "DialogModInvalidMessage": "Вказаний каталог не містить модифікації!", - "DialogModDeleteNoParentMessage": "Не видалено: Не знайдено батьківський каталог для модифікації \"{0}\"!", - "DialogDlcNoDlcErrorMessage": "Зазначений файл не містить DLC для вибраного заголовку!", - "DialogPerformanceCheckLoggingEnabledMessage": "Ви увімкнули журнал налагодження, призначений лише для розробників.", - "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальної продуктивності рекомендується вимкнути ведення журналу налагодження. Ви хочете вимкнути ведення журналу налагодження зараз?", - "DialogPerformanceCheckShaderDumpEnabledMessage": "Ви увімкнули скидання шейдерів, призначений лише для розробників.", - "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Для оптимальної продуктивності рекомендується вимкнути скидання шейдерів. Ви хочете вимкнути скидання шейдерів зараз?", - "DialogLoadAppGameAlreadyLoadedMessage": "Гру вже завантажено", - "DialogLoadAppGameAlreadyLoadedSubMessage": "Зупиніть емуляцію або закрийте емулятор перед запуском іншої гри.", - "DialogUpdateAddUpdateErrorMessage": "Зазначений файл не містить оновлення для вибраного заголовка!", - "DialogSettingsBackendThreadingWarningTitle": "Попередження - потокове керування сервером", - "DialogSettingsBackendThreadingWarningMessage": "Ryujinx потрібно перезапустити після зміни цього параметра, щоб він застосовувався повністю. Залежно від вашої платформи вам може знадобитися вручну вимкнути власну багатопотоковість драйвера під час використання Ryujinx.", - "DialogModManagerDeletionWarningMessage": "Ви збираєтесь видалити модифікацію: {0}\n\nВи дійсно бажаєте продовжити?", - "DialogModManagerDeletionAllWarningMessage": "Ви збираєтесь видалити всі модифікації для цього Додатка.\n\nВи дійсно бажаєте продовжити?", - "SettingsTabGraphicsFeaturesOptions": "Особливості", - "SettingsTabGraphicsBackendMultithreading": "Багатопотоковість графічного сервера:", - "CommonAuto": "Авто", - "CommonOff": "Вимкнути", - "CommonOn": "Увімкнути", - "InputDialogYes": "Так", - "InputDialogNo": "Ні", - "DialogProfileInvalidProfileNameErrorMessage": "Ім'я файлу містить неприпустимі символи. Будь ласка, спробуйте ще раз.", - "MenuBarOptionsPauseEmulation": "Пауза", - "MenuBarOptionsResumeEmulation": "Продовжити", - "AboutUrlTooltipMessage": "Натисніть, щоб відкрити сайт Ryujinx у браузері за замовчування.", - "AboutDisclaimerMessage": "Ryujinx жодним чином не пов’язано з Nintendo™,\nчи будь-яким із їхніх партнерів.", - "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) використовується в нашій емуляції Amiibo.", - "AboutPatreonUrlTooltipMessage": "Натисніть, щоб відкрити сторінку Patreon Ryujinx у вашому браузері за замовчування.", - "AboutGithubUrlTooltipMessage": "Натисніть, щоб відкрити сторінку GitHub Ryujinx у браузері за замовчуванням.", - "AboutDiscordUrlTooltipMessage": "Натисніть, щоб відкрити запрошення на сервер Discord Ryujinx у браузері за замовчуванням.", - "AboutTwitterUrlTooltipMessage": "Натисніть, щоб відкрити сторінку Twitter Ryujinx у браузері за замовчуванням.", - "AboutRyujinxAboutTitle": "Про програму:", - "AboutRyujinxAboutContent": "Ryujinx — це емулятор для Nintendo Switch™.\nБудь ласка, підтримайте нас на Patreon.\nОтримуйте всі останні новини в нашому Twitter або Discord.\nРозробники, які хочуть зробити внесок, можуть дізнатися більше на нашому GitHub або в Discord.", - "AboutRyujinxMaintainersTitle": "Підтримується:", - "AboutRyujinxMaintainersContentTooltipMessage": "Натисніть, щоб відкрити сторінку співавторів у вашому браузері за замовчування.", - "AboutRyujinxSupprtersTitle": "Підтримується на Patreon:", - "AmiiboSeriesLabel": "Серія Amiibo", - "AmiiboCharacterLabel": "Персонаж", - "AmiiboScanButtonLabel": "Сканувати", - "AmiiboOptionsShowAllLabel": "Показати всі Amiibo", - "AmiiboOptionsUsRandomTagLabel": "Хитрість: Використовувати випадковий тег Uuid", - "DlcManagerTableHeadingEnabledLabel": "Увімкнено", - "DlcManagerTableHeadingTitleIdLabel": "ID заголовка", - "DlcManagerTableHeadingContainerPathLabel": "Шлях до контейнеру", - "DlcManagerTableHeadingFullPathLabel": "Повний шлях", - "DlcManagerRemoveAllButton": "Видалити все", - "DlcManagerEnableAllButton": "Увімкнути всі", - "DlcManagerDisableAllButton": "Вимкнути всі", - "ModManagerDeleteAllButton": "Видалити все", - "MenuBarOptionsChangeLanguage": "Змінити мову", - "MenuBarShowFileTypes": "Показати типи файлів", - "CommonSort": "Сортувати", - "CommonShowNames": "Показати назви", - "CommonFavorite": "Вибрані", - "OrderAscending": "За зростанням", - "OrderDescending": "За спаданням", - "SettingsTabGraphicsFeatures": "Функції та вдосконалення", - "ErrorWindowTitle": "Вікно помилок", - "ToggleDiscordTooltip": "Виберіть, чи відображати Ryujinx у вашій «поточній грі» в Discord", - "AddGameDirBoxTooltip": "Введіть каталог ігор, щоб додати до списку", - "AddGameDirTooltip": "Додати каталог гри до списку", - "RemoveGameDirTooltip": "Видалити вибраний каталог гри", - "AddAutoloadDirBoxTooltip": "Enter an autoload directory to add to the list", - "AddAutoloadDirTooltip": "Add an autoload directory to the list", - "RemoveAutoloadDirTooltip": "Remove selected autoload directory", - "CustomThemeCheckTooltip": "Використовуйте користувацьку тему Avalonia для графічного інтерфейсу, щоб змінити вигляд меню емулятора", - "CustomThemePathTooltip": "Шлях до користувацької теми графічного інтерфейсу", - "CustomThemeBrowseTooltip": "Огляд користувацької теми графічного інтерфейсу", - "DockModeToggleTooltip": "У режимі док-станції емульована система веде себе як приєднаний Nintendo Switch. Це покращує точність графіки в більшості ігор. І навпаки, вимкнення цього призведе до того, що емульована система поводитиметься як портативний комутатор Nintendo, погіршуючи якість графіки.\n\nНалаштуйте елементи керування для гравця 1, якщо плануєте використовувати режим док-станції; налаштуйте ручні елементи керування, якщо плануєте використовувати портативний режим.\n\nЗалиште увімкненим, якщо не впевнені.", - "DirectKeyboardTooltip": "Підтримка прямого доступу до клавіатури (HID). Надає іграм доступ до клавіатури для вводу тексту.\n\nПрацює тільки з іграми, які підтримують клавіатуру на обладнанні Switch.\n\nЗалиште вимкненим, якщо не впевнені.", - "DirectMouseTooltip": "Підтримка прямого доступу до миші (HID). Надає іграм доступ до миші, як пристрій вказування.\n\nПрацює тільки з іграми, які підтримують мишу на обладнанні Switch, їх небагато.\n\nФункціонал сенсорного екрана може не працювати, якщо функція ввімкнена.\n\nЗалиште вимкненим, якщо не впевнені.", - "RegionTooltip": "Змінити регіон системи", - "LanguageTooltip": "Змінити мову системи", - "TimezoneTooltip": "Змінити часовий пояс системи", - "TimeTooltip": "Змінити час системи", - "VSyncToggleTooltip": "Емульована вертикальна синхронізація консолі. По суті, обмежувач кадрів для більшості ігор; його вимкнення може призвести до того, що ігри працюватимуть на вищій швидкості, екрани завантаження триватимуть довше чи зупинятимуться.\n\nМожна перемикати в грі гарячою клавішею (За умовчанням F1). Якщо ви плануєте вимкнути функцію, рекомендуємо зробити це через гарячу клавішу.\n\nЗалиште увімкненим, якщо не впевнені.", - "PptcToggleTooltip": "Зберігає перекладені функції JIT, щоб їх не потрібно було перекладати кожного разу, коли гра завантажується.\n\nЗменшує заїкання та значно прискорює час завантаження після першого завантаження гри.\n\nЗалиште увімкненим, якщо не впевнені.", - "LowPowerPptcToggleTooltip": "Load the PPTC using a third of the amount of cores.", - "FsIntegrityToggleTooltip": "Перевіряє наявність пошкоджених файлів під час завантаження гри, і якщо виявлено пошкоджені файли, показує помилку хешу в журналі.\n\nНе впливає на продуктивність і призначений для усунення несправностей.\n\nЗалиште увімкненим, якщо не впевнені.", - "AudioBackendTooltip": "Змінює серверну частину, яка використовується для відтворення аудіо.\n\nSDL2 є кращим, тоді як OpenAL і SoundIO використовуються як резервні варіанти. Dummy не матиме звуку.\n\nВстановіть SDL2, якщо не впевнені.", - "MemoryManagerTooltip": "Змінює спосіб відображення та доступу до гостьової пам’яті. Значно впливає на продуктивність емульованого ЦП.\n\nВстановіть «Неперевірений хост», якщо не впевнені.", - "MemoryManagerSoftwareTooltip": "Використовує програмну таблицю сторінок для перекладу адрес. Найвища точність, але найповільніша продуктивність.", - "MemoryManagerHostTooltip": "Пряме відображення пам'яті в адресному просторі хосту. Набагато швидша компіляція та виконання JIT.", - "MemoryManagerUnsafeTooltip": "Пряме відображення пам’яті, але не маскує адресу в гостьовому адресному просторі перед доступом. Швидше, але ціною безпеки. Гостьова програма може отримати доступ до пам’яті з будь-якого місця в Ryujinx, тому запускайте в цьому режимі лише програми, яким ви довіряєте.", - "UseHypervisorTooltip": "Використання гіпервізор замість JIT. Значно покращує продуктивність, коли доступний, але може бути нестабільним у поточному стані.", - "DRamTooltip": "Використовує альтернативний макет MemoryMode для імітації моделі розробки Switch.\n\nЦе корисно лише для пакетів текстур з вищою роздільною здатністю або модифікацій із роздільною здатністю 4K. НЕ покращує продуктивність.\n\nЗалиште вимкненим, якщо не впевнені.", - "IgnoreMissingServicesTooltip": "Ігнорує нереалізовані служби Horizon OS. Це може допомогти в обході збоїв під час завантаження певних ігор.\n\nЗалиште вимкненим, якщо не впевнені.", - "IgnoreAppletTooltip": "Зовнішнє діалогове вікно \"Аплет контролера\" не з’являтиметься, якщо геймпад буде від’єднано під час гри. Не буде запиту закрити діалогове вікно чи налаштувати новий контролер. Після повторного підключення раніше від’єднаного контролера гра автоматично відновиться.", - "GraphicsBackendThreadingTooltip": "Виконує команди графічного сервера в другому потоці.\n\nПрискорює компіляцію шейдерів, зменшує затримки та покращує продуктивність драйверів GPU без власної підтримки багатопоточності. Трохи краща продуктивність на драйверах з багатопотоковістю.\nВстановіть значення «Авто», якщо не впевнені", - "GalThreadingTooltip": "Виконує команди графічного сервера в другому потоці.\n\nПрискорює компіляцію шейдерів, зменшує затримки та покращує продуктивність драйверів GPU без власної підтримки багатопоточності. Трохи краща продуктивність на драйверах з багатопотоковістю.\n\nВстановіть значення «Авто», якщо не впевнені.", - "ShaderCacheToggleTooltip": "Зберігає кеш дискового шейдера, що зменшує затримки під час наступних запусків.\n\nЗалиште увімкненим, якщо не впевнені.", - "ResolutionScaleTooltip": "Множить роздільну здатність гри.\n\nДеякі ігри можуть не працювати з цією функцією, і виглядатимуть піксельними; для цих ігор треба знайти модифікації, що зупиняють згладжування або підвищують роздільну здатність. Для останніх модифікацій, вибирайте \"Native\".\n\nЦей параметр можна міняти коли гра запущена кліком на \"Застосувати\"; ви можете перемістити вікно налаштувань і поекспериментувати з видом гри.\n\nМайте на увазі, що 4x це занадто для будь-якого комп'ютера.", - "ResolutionScaleEntryTooltip": "Масштаб роздільної здатності з плаваючою комою, наприклад 1,5. Не інтегральні масштаби, швидше за все, спричинять проблеми або збій.", - "AnisotropyTooltip": "Рівень анізотропної фільтрації. Встановіть на «Авто», щоб використовувати значення, яке вимагає гра.", - "AspectRatioTooltip": "Співвідношення сторін застосовано до вікна рендера.\n\nМіняйте тільки, якщо використовуєте модифікацію співвідношення сторін для гри, інакше графіка буде розтягнута.\n\nЗалиште на \"16:9\", якщо не впевнені.", - "ShaderDumpPathTooltip": "Шлях скидання графічних шейдерів", - "FileLogTooltip": "Зберігає журнал консолі у файл журналу на диску. Не впливає на продуктивність.", - "StubLogTooltip": "Друкує повідомлення журналу-заглушки на консолі. Не впливає на продуктивність.", - "InfoLogTooltip": "Друкує повідомлення інформаційного журналу на консолі. Не впливає на продуктивність.", - "WarnLogTooltip": "Друкує повідомлення журналу попереджень у консолі. Не впливає на продуктивність.", - "ErrorLogTooltip": "Друкує повідомлення журналу помилок у консолі. Не впливає на продуктивність.", - "TraceLogTooltip": "Друкує повідомлення журналу трасування на консолі. Не впливає на продуктивність.", - "GuestLogTooltip": "Друкує повідомлення журналу гостей у консолі. Не впливає на продуктивність.", - "FileAccessLogTooltip": "Друкує повідомлення журналу доступу до файлів у консолі.", - "FSAccessLogModeTooltip": "Вмикає виведення журналу доступу до FS на консоль. Можливі режими 0-3", - "DeveloperOptionTooltip": "Використовуйте з обережністю", - "OpenGlLogLevel": "Потрібно увімкнути відповідні рівні журналу", - "DebugLogTooltip": "Друкує повідомлення журналу налагодження на консолі.\n\nВикористовуйте це лише за спеціальною вказівкою співробітника, оскільки це ускладнить читання журналів і погіршить роботу емулятора.", - "LoadApplicationFileTooltip": "Відкриває файловий провідник, щоб вибрати для завантаження сумісний файл Switch", - "LoadApplicationFolderTooltip": "Відкриває файловий провідник, щоб вибрати сумісну з комутатором розпаковану програму для завантаження", - "LoadDlcFromFolderTooltip": "Open a file explorer to choose one or more folders to bulk load DLC from", - "LoadTitleUpdatesFromFolderTooltip": "Open a file explorer to choose one or more folders to bulk load title updates from", - "OpenRyujinxFolderTooltip": "Відкриває папку файлової системи Ryujinx", - "OpenRyujinxLogsTooltip": "Відкриває папку, куди записуються журнали", - "ExitTooltip": "Виходить з Ryujinx", - "OpenSettingsTooltip": "Відкриває вікно налаштувань", - "OpenProfileManagerTooltip": "Відкриває вікно диспетчера профілів користувачів", - "StopEmulationTooltip": "Зупиняє емуляцію поточної гри та повертається до вибору гри", - "CheckUpdatesTooltip": "Перевіряє наявність оновлень для Ryujinx", - "OpenAboutTooltip": "Відкриває вікно «Про програму».", - "GridSize": "Розмір сітки", - "GridSizeTooltip": "Змінити розмір елементів сітки", - "SettingsTabSystemSystemLanguageBrazilianPortuguese": "Португальська (Бразилія)", - "AboutRyujinxContributorsButtonHeader": "Переглянути всіх співавторів", - "SettingsTabSystemAudioVolume": "Гучність: ", - "AudioVolumeTooltip": "Змінити гучність звуку", - "SettingsTabSystemEnableInternetAccess": "Гостьовий доступ до Інтернету/режим LAN", - "EnableInternetAccessTooltip": "Дозволяє емульованій програмі підключатися до Інтернету.\n\nІгри з режимом локальної мережі можуть підключатися одна до одної, якщо це увімкнено, і системи підключені до однієї точки доступу. Сюди входять і справжні консолі.\n\nНЕ дозволяє підключатися до серверів Nintendo. Може призвести до збою в деяких іграх, які намагаються підключитися до Інтернету.\n\nЗалиште вимкненим, якщо не впевнені.", - "GameListContextMenuManageCheatToolTip": "Керування читами", - "GameListContextMenuManageCheat": "Керування читами", - "GameListContextMenuManageModToolTip": "Керування модами", - "GameListContextMenuManageMod": "Керування модами", - "ControllerSettingsStickRange": "Діапазон:", - "DialogStopEmulationTitle": "Ryujinx - Зупинити емуляцію", - "DialogStopEmulationMessage": "Ви впевнені, що хочете зупинити емуляцію?", - "SettingsTabCpu": "ЦП", - "SettingsTabAudio": "Аудіо", - "SettingsTabNetwork": "Мережа", - "SettingsTabNetworkConnection": "Підключення до мережі", - "SettingsTabCpuCache": "Кеш ЦП", - "SettingsTabCpuMemory": "Пам'ять ЦП", - "DialogUpdaterFlatpakNotSupportedMessage": "Будь ласка, оновіть Ryujinx через FlatHub.", - "UpdaterDisabledWarningTitle": "Програму оновлення вимкнено!", - "ControllerSettingsRotate90": "Повернути на 90° за годинниковою стрілкою", - "IconSize": "Розмір значка", - "IconSizeTooltip": "Змінити розмір значків гри", - "MenuBarOptionsShowConsole": "Показати консоль", - "ShaderCachePurgeError": "Помилка очищення кешу шейдера {0}: {1}", - "UserErrorNoKeys": "Ключі не знайдено", - "UserErrorNoFirmware": "Прошивка не знайдена", - "UserErrorFirmwareParsingFailed": "Помилка аналізу прошивки", - "UserErrorApplicationNotFound": "Додаток не знайдено", - "UserErrorUnknown": "Невідома помилка", - "UserErrorUndefined": "Невизначена помилка", - "UserErrorNoKeysDescription": "Ryujinx не вдалося знайти ваш файл «prod.keys».", - "UserErrorNoFirmwareDescription": "Ryujinx не вдалося знайти встановлену прошивку", - "UserErrorFirmwareParsingFailedDescription": "Ryujinx не вдалося проаналізувати прошивку. Зазвичай це спричинено застарілими ключами.", - "UserErrorApplicationNotFoundDescription": "Ryujinx не вдалося знайти дійсний додаток за вказаним шляхом", - "UserErrorUnknownDescription": "Сталася невідома помилка!", - "UserErrorUndefinedDescription": "Сталася невизначена помилка! Цього не повинно статися, зверніться до розробника!", - "OpenSetupGuideMessage": "Відкрити посібник із налаштування", - "NoUpdate": "Немає оновлень", - "TitleUpdateVersionLabel": "Версія {0} - {1}", - "TitleBundledUpdateVersionLabel": "Bundled: Version {0}", - "TitleBundledDlcLabel": "Bundled:", - "RyujinxInfo": "Ryujin x - Інформація", - "RyujinxConfirm": "Ryujinx - Підтвердження", - "FileDialogAllTypes": "Всі типи", - "Never": "Ніколи", - "SwkbdMinCharacters": "Мінімальна кількість символів: {0}", - "SwkbdMinRangeCharacters": "Має бути {0}-{1} символів", - "SoftwareKeyboard": "Програмна клавіатура", - "SoftwareKeyboardModeNumeric": "Повинно бути лише 0-9 або “.”", - "SoftwareKeyboardModeAlphabet": "Повинно бути лише не CJK-символи", - "SoftwareKeyboardModeASCII": "Повинно бути лише ASCII текст", - "ControllerAppletControllers": "Підтримувані контролери:", - "ControllerAppletPlayers": "Гравці:", - "ControllerAppletDescription": "Поточна конфігурація невірна. Відкрийте налаштування та переналаштуйте Ваші дані.", - "ControllerAppletDocked": "Встановлений режим в док-станції. Вимкніть портативні контролери.", - "UpdaterRenaming": "Перейменування старих файлів...", - "UpdaterRenameFailed": "Програмі оновлення не вдалося перейменувати файл: {0}", - "UpdaterAddingFiles": "Додавання нових файлів...", - "UpdaterExtracting": "Видобування оновлення...", - "UpdaterDownloading": "Завантаження оновлення...", - "Game": "Гра", - "Docked": "Док-станція", - "Handheld": "Портативний", - "ConnectionError": "Помилка з'єднання.", - "AboutPageDeveloperListMore": "{0} та інші...", - "ApiError": "Помилка API.", - "LoadingHeading": "Завантаження {0}", - "CompilingPPTC": "Компіляція PTC", - "CompilingShaders": "Компіляція шейдерів", - "AllKeyboards": "Всі клавіатури", - "OpenFileDialogTitle": "Виберіть підтримуваний файл для відкриття", - "OpenFolderDialogTitle": "Виберіть теку з розпакованою грою", - "AllSupportedFormats": "Усі підтримувані формати", - "RyujinxUpdater": "Програма оновлення Ryujinx", - "SettingsTabHotkeys": "Гарячі клавіші клавіатури", - "SettingsTabHotkeysHotkeys": "Гарячі клавіші клавіатури", - "SettingsTabHotkeysToggleVsyncHotkey": "Увімк/вимк вертикальну синхронізацію:", - "SettingsTabHotkeysScreenshotHotkey": "Знімок екрана:", - "SettingsTabHotkeysShowUiHotkey": "Показати інтерфейс:", - "SettingsTabHotkeysPauseHotkey": "Пауза:", - "SettingsTabHotkeysToggleMuteHotkey": "Вимкнути звук:", - "ControllerMotionTitle": "Налаштування керування рухом", - "ControllerRumbleTitle": "Налаштування вібрації", - "SettingsSelectThemeFileDialogTitle": "Виберіть файл теми", - "SettingsXamlThemeFile": "Файл теми Xaml", - "AvatarWindowTitle": "Керування обліковими записами - Аватар", - "Amiibo": "Amiibo", - "Unknown": "Невідомо", - "Usage": "Використання", - "Writable": "Можливість запису", - "SelectDlcDialogTitle": "Виберіть файли DLC", - "SelectUpdateDialogTitle": "Виберіть файли оновлення", - "SelectModDialogTitle": "Виберіть теку з модами", - "UserProfileWindowTitle": "Менеджер профілів користувачів", - "CheatWindowTitle": "Менеджер читів", - "DlcWindowTitle": "Менеджер вмісту для завантаження", - "ModWindowTitle": "Керувати модами для {0} ({1})", - "UpdateWindowTitle": "Менеджер оновлення назв", - "XCITrimmerTrim": "Trim", - "XCITrimmerUntrim": "Untrim", - "UpdateWindowUpdateAddedMessage": "{0} new update(s) added", - "UpdateWindowBundledContentNotice": "Bundled updates cannot be removed, only disabled.", - "CheatWindowHeading": "Коди доступні для {0} [{1}]", - "BuildId": "ID збірки:", - "DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.", - "DlcWindowHeading": "Вміст для завантаження, доступний для {1} ({2}): {0}", - "DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added", - "AutoloadDlcAddedMessage": "{0} new downloadable content(s) added", - "AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed", - "AutoloadUpdateAddedMessage": "{0} new update(s) added", - "AutoloadUpdateRemovedMessage": "{0} missing update(s) removed", - "ModWindowHeading": "{0} мод(ів)", - "UserProfilesEditProfile": "Редагувати вибране", - "Cancel": "Скасувати", - "Save": "Зберегти", - "Discard": "Скасувати", - "Paused": "Призупинено", - "UserProfilesSetProfileImage": "Встановити зображення профілю", - "UserProfileEmptyNameError": "Імʼя обовʼязкове", - "UserProfileNoImageError": "Зображення профілю обовʼязкове", - "GameUpdateWindowHeading": "{0} Доступні оновлення для {1} ({2})", - "SettingsTabHotkeysResScaleUpHotkey": "Збільшити роздільність:", - "SettingsTabHotkeysResScaleDownHotkey": "Зменшити роздільність:", - "UserProfilesName": "Імʼя", - "UserProfilesUserId": "ID користувача:", - "SettingsTabGraphicsBackend": "Графічний сервер", - "SettingsTabGraphicsBackendTooltip": "Виберіть backend графіки, що буде використовуватись в емуляторі.\n\n\"Vulkan\" краще для всіх сучасних відеокарт, якщо драйвери вчасно оновлюються. У Vulkan також швидше компілюються шейдери (менше \"заїкання\" зображення) на відеокартах всіх компаній.\n\n\"OpenGL\" може дати кращі результати на старих відеокартах Nvidia, старих відеокартах AMD на Linux, або на відеокартах з маленькою кількістю VRAM, але \"заїкання\" через компіляцію шейдерів будуть частіші.\n\nЯкщо не впевнені, встановіть на \"Vulkan\". Встановіть на \"OpenGL\", якщо Ваша відеокарта не підтримує Vulkan навіть на останніх драйверах.", - "SettingsEnableTextureRecompression": "Увімкнути рекомпресію текстури", - "SettingsEnableTextureRecompressionTooltip": "Стискає текстури ASTC, щоб зменшити використання VRAM.\n\nЦим форматом текстур користуються такі ігри, як Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder і The Legend of Zelda: Tears of the Kingdom.\n\nЦі ігри, скоріше всього крашнуться на відеокартах з розміром VRAM в 4 Гб і менше.\n\nВмикайте тільки якщо у Вас закінчується VRAM на цих іграх. Залиште на \"Вимкнути\", якщо не впевнені.", - "SettingsTabGraphicsPreferredGpu": "Бажаний GPU", - "SettingsTabGraphicsPreferredGpuTooltip": "Виберіть відеокарту, яка використовуватиметься з графічним сервером Vulkan.\n\nНе впливає на графічний процесор, який використовуватиме OpenGL.\n\nВстановіть графічний процесор, позначений як «dGPU», якщо не впевнені. Якщо такого немає, не чіпайте.", - "SettingsAppRequiredRestartMessage": "Необхідно перезапустити Ryujinx", - "SettingsGpuBackendRestartMessage": "Налаштування графічного сервера або GPU було змінено. Для цього знадобиться перезапуск", - "SettingsGpuBackendRestartSubMessage": "Бажаєте перезапустити зараз?", - "RyujinxUpdaterMessage": "Бажаєте оновити Ryujinx до останньої версії?", - "SettingsTabHotkeysVolumeUpHotkey": "Збільшити гучність:", - "SettingsTabHotkeysVolumeDownHotkey": "Зменшити гучність:", - "SettingsEnableMacroHLE": "Увімкнути макрос HLE", - "SettingsEnableMacroHLETooltip": "Високорівнева емуляція коду макросу GPU.\n\nПокращує продуктивність, але може викликати графічні збої в деяких іграх.\n\nЗалиште увімкненим, якщо не впевнені.", - "SettingsEnableColorSpacePassthrough": "Наскрізний колірний простір", - "SettingsEnableColorSpacePassthroughTooltip": "Дозволяє серверу Vulkan передавати інформацію про колір без вказівки колірного простору. Для користувачів з екранами з широкою гамою це може призвести до більш яскравих кольорів, але шляхом втрати коректності передачі кольору.", - "VolumeShort": "Гуч.", - "UserProfilesManageSaves": "Керувати збереженнями", - "DeleteUserSave": "Ви хочете видалити збереження користувача для цієї гри?", - "IrreversibleActionNote": "Цю дію не можна скасувати.", - "SaveManagerHeading": "Керувати збереженнями для {0}", - "SaveManagerTitle": "Менеджер збереження", - "Name": "Назва", - "Size": "Розмір", - "Search": "Пошук", - "UserProfilesRecoverLostAccounts": "Відновлення втрачених облікових записів", - "Recover": "Відновити", - "UserProfilesRecoverHeading": "Знайдено збереження для наступних облікових записів", - "UserProfilesRecoverEmptyList": "Немає профілів для відновлення", - "GraphicsAATooltip": "Застосовує згладження до рендера гри.\n\nFXAA розмиє більшість зображення, а SMAA спробує знайти нерівні краї та згладити їх.\n\nНе рекомендується використовувати разом з фільтром масштабування FSR.\n\nЦю опцію можна міняти коли гра запущена кліком на \"Застосувати; ви можете відсунути вікно налаштувань і поекспериментувати з видом гри.\n\nЗалиште на \"Немає\", якщо не впевнені.", - "GraphicsAALabel": "Згладжування:", - "GraphicsScalingFilterLabel": "Фільтр масштабування:", - "GraphicsScalingFilterTooltip": "Виберіть фільтр масштабування, що використається при збільшенні роздільної здатності.\n\n\"Білінійний\" добре виглядає в 3D іграх, і хороше налаштування за умовчуванням.\n\n\"Найближчий\" рекомендується для ігор з піксель-артом.\n\n\"FSR 1.0\" - це просто фільтр різкості, не рекомендується використовувати разом з FXAA або SMAA.\n\nЦю опцію можна міняти коли гра запущена кліком на \"Застосувати; ви можете відсунути вікно налаштувань і поекспериментувати з видом гри.\n\nЗалиште на \"Білінійний\", якщо не впевнені.", - "GraphicsScalingFilterBilinear": "Білінійний", - "GraphicsScalingFilterNearest": "Найближчий", - "GraphicsScalingFilterFsr": "FSR", - "GraphicsScalingFilterArea": "Area", - "GraphicsScalingFilterLevelLabel": "Рівень", - "GraphicsScalingFilterLevelTooltip": "Встановити рівень різкості в FSR 1.0. Чим вище - тим різкіше.", - "SmaaLow": "SMAA Низький", - "SmaaMedium": "SMAA Середній", - "SmaaHigh": "SMAA Високий", - "SmaaUltra": "SMAA Ультра", - "UserEditorTitle": "Редагувати користувача", - "UserEditorTitleCreate": "Створити користувача", - "SettingsTabNetworkInterface": "Мережевий інтерфейс:", - "NetworkInterfaceTooltip": "Мережевий інтерфейс, що використовується для LAN/LDN.\n\nРазом з VPN або XLink Kai, і грою що підтримує LAN, може імітувати з'єднання в однаковій мережі через Інтернет.", - "NetworkInterfaceDefault": "Стандартний", - "PackagingShaders": "Пакування шейдерів", - "AboutChangelogButton": "Переглянути журнал змін на GitHub", - "AboutChangelogButtonTooltipMessage": "Клацніть, щоб відкрити журнал змін для цієї версії у стандартному браузері.", - "SettingsTabNetworkMultiplayer": "Мережева гра", - "MultiplayerMode": "Режим:", - "MultiplayerModeTooltip": "Змінити LDN мультиплеєру.\n\nLdnMitm змінить функціонал бездротової/локальної гри в іграх, щоб вони працювали так, ніби це LAN, що дозволяє локальні підключення в тій самій мережі з іншими екземплярами Ryujinx та хакнутими консолями Nintendo Switch, які мають встановлений модуль ldn_mitm.\n\nМультиплеєр вимагає, щоб усі гравці були на одній і тій же версії гри (наприклад Super Smash Bros. Ultimate v13.0.1 не зможе під'єднатися до v13.0.0).\n\nЗалиште на \"Вимкнено\", якщо не впевнені, ", - "MultiplayerModeDisabled": "Вимкнено", - "MultiplayerModeLdnMitm": "ldn_mitm" -} +{ + "Language": "Українська", + "MenuBarFileOpenApplet": "Відкрити аплет", + "MenuBarFileOpenAppletOpenMiiApplet": "Аплет для редагування Mii", + "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Відкрити аплет Mii Editor в автономному режимі", + "SettingsTabInputDirectMouseAccess": "Прямий доступ мишею", + "SettingsTabSystemMemoryManagerMode": "Режим диспетчера пам’яті:", + "SettingsTabSystemMemoryManagerModeSoftware": "Програмне забезпечення", + "SettingsTabSystemMemoryManagerModeHost": "Хост (швидко)", + "SettingsTabSystemMemoryManagerModeHostUnchecked": "Неперевірений хост (найшвидший, небезпечний)", + "SettingsTabSystemUseHypervisor": "Використовувати гіпервізор", + "MenuBarFile": "_Файл", + "MenuBarFileOpenFromFile": "_Завантажити програму з файлу", + "MenuBarFileOpenFromFileError": "У вибраному файлі не знайдено жодних додатків.", + "MenuBarFileOpenUnpacked": "Завантажити _розпаковану гру", + "MenuBarFileLoadDlcFromFolder": "Завантажити DLC з теки", + "MenuBarFileLoadTitleUpdatesFromFolder": "Завантажити оновлення заголовків з теки", + "MenuBarFileOpenEmuFolder": "Відкрити теку Ryujinx", + "MenuBarFileOpenLogsFolder": "Відкрити теку журналів змін", + "MenuBarFileExit": "_Вихід", + "MenuBarOptions": "_Параметри", + "MenuBarOptionsToggleFullscreen": "На весь екран", + "MenuBarOptionsStartGamesInFullscreen": "Запускати ігри на весь екран", + "MenuBarOptionsStopEmulation": "Зупинити емуляцію", + "MenuBarOptionsSettings": "_Налаштування", + "MenuBarOptionsManageUserProfiles": "_Керувати профілями користувачів", + "MenuBarActions": "_Дії", + "MenuBarOptionsSimulateWakeUpMessage": "Симулювати повідомлення про пробудження", + "MenuBarActionsScanAmiibo": "Сканувати Amiibo", + "MenuBarTools": "_Інструменти", + "MenuBarToolsInstallFirmware": "Установити прошивку", + "MenuBarFileToolsInstallFirmwareFromFile": "Установити прошивку з XCI або ZIP", + "MenuBarFileToolsInstallFirmwareFromDirectory": "Установити прошивку з теки", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", + "MenuBarToolsManageFileTypes": "Керувати типами файлів", + "MenuBarToolsInstallFileTypes": "Установити типи файлів", + "MenuBarToolsUninstallFileTypes": "Видалити типи файлів", + "MenuBarToolsXCITrimmer": "Обрізати XCI файли", + "MenuBarView": "_Вид", + "MenuBarViewWindow": "Розмір вікна", + "MenuBarViewWindow720": "720p", + "MenuBarViewWindow1080": "1080p", + "MenuBarHelp": "_Допомога", + "MenuBarHelpCheckForUpdates": "Перевірити оновлення", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", + "MenuBarHelpAbout": "Про застосунок", + "MenuSearch": "Пошук...", + "GameListHeaderFavorite": "Обране", + "GameListHeaderIcon": "Значок", + "GameListHeaderApplication": "Назва", + "GameListHeaderDeveloper": "Розробник", + "GameListHeaderVersion": "Версія", + "GameListHeaderTimePlayed": "Зіграно часу", + "GameListHeaderLastPlayed": "Востаннє зіграно", + "GameListHeaderFileExtension": "Розширення файлу", + "GameListHeaderFileSize": "Розмір файлу", + "GameListHeaderPath": "Шлях", + "GameListContextMenuOpenUserSaveDirectory": "Відкрити теку збереження користувача", + "GameListContextMenuOpenUserSaveDirectoryToolTip": "Відкриває каталог, який містить збереження користувача програми", + "GameListContextMenuOpenDeviceSaveDirectory": "Відкрити каталог пристроїв користувача", + "GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Відкриває каталог, який містить збереження пристрою програми", + "GameListContextMenuOpenBcatSaveDirectory": "Відкрити каталог користувача BCAT", + "GameListContextMenuOpenBcatSaveDirectoryToolTip": "Відкриває каталог, який містить BCAT-збереження програми", + "GameListContextMenuManageTitleUpdates": "Керування оновленнями заголовків", + "GameListContextMenuManageTitleUpdatesToolTip": "Відкриває вікно керування оновленням заголовка", + "GameListContextMenuManageDlc": "Керування DLC", + "GameListContextMenuManageDlcToolTip": "Відкриває вікно керування DLC", + "GameListContextMenuCacheManagement": "Керування кешем", + "GameListContextMenuCacheManagementPurgePptc": "Очистити кеш PPTC", + "GameListContextMenuCacheManagementPurgePptcToolTip": "Видаляє кеш PPTC програми", + "GameListContextMenuCacheManagementPurgeShaderCache": "Очистити кеш шейдерів", + "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Видаляє кеш шейдерів програми", + "GameListContextMenuCacheManagementOpenPptcDirectory": "Відкрити каталог PPTC", + "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Відкриває каталог, який містить кеш PPTC програми", + "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Відкрити каталог кешу шейдерів", + "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Відкриває каталог, який містить кеш шейдерів програми", + "GameListContextMenuExtractData": "Видобути дані", + "GameListContextMenuExtractDataExeFS": "ExeFS", + "GameListContextMenuExtractDataExeFSToolTip": "Видобуває розділ ExeFS із поточної конфігурації програми (включаючи оновлення)", + "GameListContextMenuExtractDataRomFS": "RomFS", + "GameListContextMenuExtractDataRomFSToolTip": "Видобуває розділ RomFS із поточної конфігурації програми (включаючи оновлення)", + "GameListContextMenuExtractDataLogo": "Логотип", + "GameListContextMenuExtractDataLogoToolTip": "Видобуває розділ логотипу з поточної конфігурації програми (включаючи оновлення)", + "GameListContextMenuCreateShortcut": "Створити ярлик застосунку", + "GameListContextMenuCreateShortcutToolTip": "Створити ярлик на робочому столі, який запускає вибраний застосунок", + "GameListContextMenuCreateShortcutToolTipMacOS": "Створити ярлик у каталозі macOS програм, що запускає обраний Додаток", + "GameListContextMenuOpenModsDirectory": "Відкрити теку з модами", + "GameListContextMenuOpenModsDirectoryToolTip": "Відкриває каталог, який містить модифікації Додатків", + "GameListContextMenuOpenSdModsDirectory": "Відкрити каталог модифікацій Atmosphere", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Відкриває альтернативний каталог SD-карти Atmosphere, що містить модифікації Додатків. Корисно для модифікацій, зроблених для реального обладнання.", + "GameListContextMenuTrimXCI": "Перевірка та Нарізка XCI Файлів", + "GameListContextMenuTrimXCIToolTip": "Перевірка та Нарізка XCI Файлів для збереження місця на диску", + "StatusBarGamesLoaded": "{0}/{1} ігор завантажено", + "StatusBarSystemVersion": "Версія системи: {0}", + "StatusBarXCIFileTrimming": "Обрізано XCI Файлів '{0}'", + "LinuxVmMaxMapCountDialogTitle": "Виявлено низьку межу для відображення памʼяті", + "LinuxVmMaxMapCountDialogTextPrimary": "Бажаєте збільшити значення vm.max_map_count на {0}", + "LinuxVmMaxMapCountDialogTextSecondary": "Деякі ігри можуть спробувати створити більше відображень памʼяті, ніж дозволено наразі. Ryujinx завершить роботу, щойно цей ліміт буде перевищено.", + "LinuxVmMaxMapCountDialogButtonUntilRestart": "Так, до наст. перезапуску", + "LinuxVmMaxMapCountDialogButtonPersistent": "Так, назавжди", + "LinuxVmMaxMapCountWarningTextPrimary": "Максимальна кількість відображення памʼяті менша, ніж рекомендовано.", + "LinuxVmMaxMapCountWarningTextSecondary": "Поточне значення vm.max_map_count ({0}) менше за {1}. Деякі ігри можуть спробувати створити більше відображень пам’яті, ніж дозволено наразі. Ryujinx завершить роботу, щойно цей ліміт буде перевищено.\n\nВи можете збільшити ліміт вручну або встановити pkexec, який дозволяє Ryujinx допомогти з цим.", + "Settings": "Налаштування", + "SettingsTabGeneral": "Інтерфейс користувача", + "SettingsTabGeneralGeneral": "Загальні", + "SettingsTabGeneralEnableDiscordRichPresence": "Увімкнути розширену присутність Discord", + "SettingsTabGeneralCheckUpdatesOnLaunch": "Перевіряти наявність оновлень під час запуску", + "SettingsTabGeneralShowConfirmExitDialog": "Показати діалогове вікно «Підтвердити вихід».", + "SettingsTabGeneralRememberWindowState": "Запам'ятати Розмір/Позицію вікна", + "SettingsTabGeneralShowTitleBar": "Показувати рядок заголовка (Потрібен перезапуск)", + "SettingsTabGeneralHideCursor": "Сховати вказівник:", + "SettingsTabGeneralHideCursorNever": "Ніколи", + "SettingsTabGeneralHideCursorOnIdle": "Сховати у режимі очікування", + "SettingsTabGeneralHideCursorAlways": "Завжди", + "SettingsTabGeneralGameDirectories": "Тека ігор", + "SettingsTabGeneralAutoloadDirectories": "Автозавантаження каталогів DLC/Оновлень", + "SettingsTabGeneralAutoloadNote": "DLC та Оновлення, які посилаються на відсутні файли, будуть автоматично вимкнуті.", + "SettingsTabGeneralAdd": "Додати", + "SettingsTabGeneralRemove": "Видалити", + "SettingsTabSystem": "Система", + "SettingsTabSystemCore": "Ядро", + "SettingsTabSystemSystemRegion": "Регіон системи:", + "SettingsTabSystemSystemRegionJapan": "Японія", + "SettingsTabSystemSystemRegionUSA": "США", + "SettingsTabSystemSystemRegionEurope": "Європа", + "SettingsTabSystemSystemRegionAustralia": "Австралія", + "SettingsTabSystemSystemRegionChina": "Китай", + "SettingsTabSystemSystemRegionKorea": "Корея", + "SettingsTabSystemSystemRegionTaiwan": "Тайвань", + "SettingsTabSystemSystemLanguage": "Мова системи:", + "SettingsTabSystemSystemLanguageJapanese": "Японська", + "SettingsTabSystemSystemLanguageAmericanEnglish": "Англійська (США)", + "SettingsTabSystemSystemLanguageFrench": "Французька", + "SettingsTabSystemSystemLanguageGerman": "Німецька", + "SettingsTabSystemSystemLanguageItalian": "Італійська", + "SettingsTabSystemSystemLanguageSpanish": "Іспанська", + "SettingsTabSystemSystemLanguageChinese": "Китайська", + "SettingsTabSystemSystemLanguageKorean": "Корейська", + "SettingsTabSystemSystemLanguageDutch": "Нідерландська", + "SettingsTabSystemSystemLanguagePortuguese": "Португальська", + "SettingsTabSystemSystemLanguageRussian": "Російська", + "SettingsTabSystemSystemLanguageTaiwanese": "Тайванська", + "SettingsTabSystemSystemLanguageBritishEnglish": "Англійська (Великобританія)", + "SettingsTabSystemSystemLanguageCanadianFrench": "Французька (Канада)", + "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Іспанська (Латиноамериканська)", + "SettingsTabSystemSystemLanguageSimplifiedChinese": "Спрощена китайська", + "SettingsTabSystemSystemLanguageTraditionalChinese": "Традиційна китайська", + "SettingsTabSystemSystemTimeZone": "Часовий пояс системи:", + "SettingsTabSystemSystemTime": "Час системи:", + "SettingsTabSystemVSyncMode": "Вертикальна синхронізація (VSync):", + "SettingsTabSystemEnableCustomVSyncInterval": "Увімкнути користувацьку частоту оновлення (Експериментально)", + "SettingsTabSystemVSyncModeSwitch": "Switch", + "SettingsTabSystemVSyncModeUnbounded": "Безмежна", + "SettingsTabSystemVSyncModeCustom": "Користувацька", + "SettingsTabSystemVSyncModeTooltip": "Емульована вертикальна синхронізація. 'Switch' емулює частоту оновлення Switch 60 Гц. 'Безмежна' — частота оновлення не матиме обмежень.", + "SettingsTabSystemVSyncModeTooltipCustom": "Емульована вертикальна синхронізація. 'Switch' емулює частоту оновлення Switch 60 Гц. 'Безмежна' — частота оновлення не матиме обмежень. 'Користувацька' емулює вказану користувацьку частоту оновлення.", + "SettingsTabSystemEnableCustomVSyncIntervalTooltip": "Дозволяє користувачу вказати емульовану частоту оновлення. У деяких іграх це може прискорити або сповільнити логіку гри. У інших іграх це може дозволити обмежити FPS на певні кратні частоти оновлення або призвести до непередбачуваної поведінки. Це експериментальна функція, без гарантій того, як це вплине на ігровий процес. \n\nЗалиште ВИМКНЕНИМ, якщо не впевнені.", + "SettingsTabSystemCustomVSyncIntervalValueTooltip": "Цільове значення користувацької частоти оновлення.", + "SettingsTabSystemCustomVSyncIntervalSliderTooltip": "Користувацька частота оновлення, як відсоток від стандартної частоти оновлення Switch.", + "SettingsTabSystemCustomVSyncIntervalPercentage": "Користувацька частота оновлення %:", + "SettingsTabSystemCustomVSyncIntervalValue": "Значення користувацька частота оновлення:", + "SettingsTabSystemEnablePptc": "PPTC (профільований постійний кеш перекладу)", + "SettingsTabSystemEnableLowPowerPptc": "Low-power PPTC", + "SettingsTabSystemEnableFsIntegrityChecks": "Перевірка цілісності FS", + "SettingsTabSystemAudioBackend": "Аудіосистема:", + "SettingsTabSystemAudioBackendDummy": "Dummy", + "SettingsTabSystemAudioBackendOpenAL": "OpenAL", + "SettingsTabSystemAudioBackendSoundIO": "SoundIO", + "SettingsTabSystemAudioBackendSDL2": "SDL2", + "SettingsTabSystemHacks": "Хитрощі", + "SettingsTabSystemHacksNote": " (може викликати нестабільність)", + "SettingsTabSystemDramSize": "Використовувати альтернативне розташування пам'яті (для розробників)", + "SettingsTabSystemDramSize4GiB": "4Гб", + "SettingsTabSystemDramSize6GiB": "6Гб", + "SettingsTabSystemDramSize8GiB": "8Гб", + "SettingsTabSystemDramSize12GiB": "12Гб", + "SettingsTabSystemIgnoreMissingServices": "Ігнорувати відсутні служби", + "SettingsTabSystemIgnoreApplet": "Ігнорувати Аплет", + "SettingsTabGraphics": "Графіка", + "SettingsTabGraphicsAPI": "Графічний API", + "SettingsTabGraphicsEnableShaderCache": "Увімкнути кеш шейдерів", + "SettingsTabGraphicsAnisotropicFiltering": "Анізотропна фільтрація:", + "SettingsTabGraphicsAnisotropicFilteringAuto": "Авто", + "SettingsTabGraphicsAnisotropicFiltering2x": "2x", + "SettingsTabGraphicsAnisotropicFiltering4x": "4x", + "SettingsTabGraphicsAnisotropicFiltering8x": "8x", + "SettingsTabGraphicsAnisotropicFiltering16x": "16x", + "SettingsTabGraphicsResolutionScale": "Роздільна здатність:", + "SettingsTabGraphicsResolutionScaleCustom": "Користувацька (не рекомендовано)", + "SettingsTabGraphicsResolutionScaleNative": "Стандартний (720p/1080p)", + "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", + "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", + "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p) (Не рекомендується)", + "SettingsTabGraphicsAspectRatio": "Співвідношення сторін:", + "SettingsTabGraphicsAspectRatio4x3": "4:3", + "SettingsTabGraphicsAspectRatio16x9": "16:9", + "SettingsTabGraphicsAspectRatio16x10": "16:10", + "SettingsTabGraphicsAspectRatio21x9": "21:9", + "SettingsTabGraphicsAspectRatio32x9": "32:9", + "SettingsTabGraphicsAspectRatioStretch": "Розтягнути до розміру вікна", + "SettingsTabGraphicsDeveloperOptions": "Параметри розробника", + "SettingsTabGraphicsShaderDumpPath": "Шлях скидання графічного шейдера:", + "SettingsTabLogging": "Налагодження", + "SettingsTabLoggingLogging": "Налагодження", + "SettingsTabLoggingEnableLoggingToFile": "Увімкнути налагодження у файл", + "SettingsTabLoggingEnableStubLogs": "Увімкнути журнали заглушки", + "SettingsTabLoggingEnableInfoLogs": "Увімкнути інформаційні журнали", + "SettingsTabLoggingEnableWarningLogs": "Увімкнути журнали попереджень", + "SettingsTabLoggingEnableErrorLogs": "Увімкнути журнали помилок", + "SettingsTabLoggingEnableTraceLogs": "Увімкнути журнали трасування", + "SettingsTabLoggingEnableGuestLogs": "Увімкнути журнали гостей", + "SettingsTabLoggingEnableFsAccessLogs": "Увімкнути журнали доступу Fs", + "SettingsTabLoggingFsGlobalAccessLogMode": "Режим журналу глобального доступу Fs:", + "SettingsTabLoggingDeveloperOptions": "Параметри розробника (УВАГА: шкодить продуктивності!)", + "SettingsTabLoggingDeveloperOptionsNote": "УВАГА: Зміна параметрів нижче негативно впливає на продуктивність", + "SettingsTabLoggingGraphicsBackendLogLevel": "Рівень журналу графічного сервера:", + "SettingsTabLoggingGraphicsBackendLogLevelNone": "Немає", + "SettingsTabLoggingGraphicsBackendLogLevelError": "Помилка", + "SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Уповільнення", + "SettingsTabLoggingGraphicsBackendLogLevelAll": "Все", + "SettingsTabLoggingEnableDebugLogs": "Увімкнути журнали налагодження", + "SettingsTabInput": "Введення", + "SettingsTabInputEnableDockedMode": "Режим док-станції", + "SettingsTabInputDirectKeyboardAccess": "Прямий доступ з клавіатури", + "SettingsButtonSave": "Зберегти", + "SettingsButtonClose": "Закрити", + "SettingsButtonOk": "Гаразд", + "SettingsButtonCancel": "Скасувати", + "SettingsButtonApply": "Застосувати", + "ControllerSettingsPlayer": "Гравець", + "ControllerSettingsPlayer1": "Гравець 1", + "ControllerSettingsPlayer2": "Гравець 2", + "ControllerSettingsPlayer3": "Гравець 3", + "ControllerSettingsPlayer4": "Гравець 4", + "ControllerSettingsPlayer5": "Гравець 5", + "ControllerSettingsPlayer6": "Гравець 6", + "ControllerSettingsPlayer7": "Гравець 7", + "ControllerSettingsPlayer8": "Гравець 8", + "ControllerSettingsHandheld": "Портативний", + "ControllerSettingsInputDevice": "Пристрій введення", + "ControllerSettingsRefresh": "Оновити", + "ControllerSettingsDeviceDisabled": "Вимкнено", + "ControllerSettingsControllerType": "Тип контролера", + "ControllerSettingsControllerTypeHandheld": "Портативний", + "ControllerSettingsControllerTypeProController": "Контролер Pro", + "ControllerSettingsControllerTypeJoyConPair": "Обидва JoyCon", + "ControllerSettingsControllerTypeJoyConLeft": "Лівий JoyCon", + "ControllerSettingsControllerTypeJoyConRight": "Правий JoyCon", + "ControllerSettingsProfile": "Профіль", + "ControllerSettingsProfileDefault": "Типовий", + "ControllerSettingsLoad": "Завантажити", + "ControllerSettingsAdd": "Додати", + "ControllerSettingsRemove": "Видалити", + "ControllerSettingsButtons": "Кнопки", + "ControllerSettingsButtonA": "A", + "ControllerSettingsButtonB": "B", + "ControllerSettingsButtonX": "X", + "ControllerSettingsButtonY": "Y", + "ControllerSettingsButtonPlus": "+", + "ControllerSettingsButtonMinus": "-", + "ControllerSettingsDPad": "Панель направлення", + "ControllerSettingsDPadUp": "Вгору", + "ControllerSettingsDPadDown": "Вниз", + "ControllerSettingsDPadLeft": "Вліво", + "ControllerSettingsDPadRight": "Вправо", + "ControllerSettingsStickButton": "Кнопка", + "ControllerSettingsStickUp": "Уверх", + "ControllerSettingsStickDown": "Униз", + "ControllerSettingsStickLeft": "Ліворуч", + "ControllerSettingsStickRight": "Праворуч", + "ControllerSettingsStickStick": "Стик", + "ControllerSettingsStickInvertXAxis": "Обернути вісь стику X", + "ControllerSettingsStickInvertYAxis": "Обернути вісь стику Y", + "ControllerSettingsStickDeadzone": "Мертва зона:", + "ControllerSettingsLStick": "Лівий джойстик", + "ControllerSettingsRStick": "Правий джойстик", + "ControllerSettingsTriggersLeft": "Тригери ліворуч", + "ControllerSettingsTriggersRight": "Тригери праворуч", + "ControllerSettingsTriggersButtonsLeft": "Кнопки тригерів ліворуч", + "ControllerSettingsTriggersButtonsRight": "Кнопки тригерів праворуч", + "ControllerSettingsTriggers": "Тригери", + "ControllerSettingsTriggerL": "L", + "ControllerSettingsTriggerR": "R", + "ControllerSettingsTriggerZL": "ZL", + "ControllerSettingsTriggerZR": "ZR", + "ControllerSettingsLeftSL": "SL", + "ControllerSettingsLeftSR": "SR", + "ControllerSettingsRightSL": "SL", + "ControllerSettingsRightSR": "SR", + "ControllerSettingsExtraButtonsLeft": "Кнопки ліворуч", + "ControllerSettingsExtraButtonsRight": "Кнопки праворуч", + "ControllerSettingsMisc": "Різне", + "ControllerSettingsTriggerThreshold": "Поріг спрацьовування:", + "ControllerSettingsMotion": "Рух", + "ControllerSettingsMotionUseCemuhookCompatibleMotion": "Використовувати рух, сумісний з CemuHook", + "ControllerSettingsMotionControllerSlot": "Слот контролера:", + "ControllerSettingsMotionMirrorInput": "Дзеркальний вхід", + "ControllerSettingsMotionRightJoyConSlot": "Правий слот JoyCon:", + "ControllerSettingsMotionServerHost": "Хост сервера:", + "ControllerSettingsMotionGyroSensitivity": "Чутливість гіроскопа:", + "ControllerSettingsMotionGyroDeadzone": "Мертва зона гіроскопа:", + "ControllerSettingsSave": "Зберегти", + "ControllerSettingsClose": "Закрити", + "KeyUnknown": "Невідома", + "KeyShiftLeft": "Shift Лівий", + "KeyShiftRight": "Shift Правий", + "KeyControlLeft": "Ctrl Лівий", + "KeyMacControlLeft": "⌃ Лівий", + "KeyControlRight": "Ctrl Правий", + "KeyMacControlRight": "⌃ Правий", + "KeyAltLeft": "Alt Лівий", + "KeyMacAltLeft": "⌥ Лівий", + "KeyAltRight": "Alt Правий", + "KeyMacAltRight": "⌥ Правий", + "KeyWinLeft": "⊞ Лівий", + "KeyMacWinLeft": "⌘ Лівий", + "KeyWinRight": "⊞ Правий", + "KeyMacWinRight": "⌘ Правий", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Вліво", + "KeyRight": "Вправо", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Пробіл", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Очистити", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Відв'язати", + "GamepadLeftStick": "L Кнопка Стіку", + "GamepadRightStick": "R Кнопка Стіку", + "GamepadLeftShoulder": "Лівий Бампер", + "GamepadRightShoulder": "Правий Бампер", + "GamepadLeftTrigger": "Лівий Тригер", + "GamepadRightTrigger": "Правий Тригер", + "GamepadDpadUp": "Вверх", + "GamepadDpadDown": "Вниз", + "GamepadDpadLeft": "Вліво", + "GamepadDpadRight": "Вправо", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Лівий Тригер 0", + "GamepadSingleRightTrigger0": "Правий Тригер 0", + "GamepadSingleLeftTrigger1": "Лівий Тригер 1", + "GamepadSingleRightTrigger1": "Правий Тригер 1", + "StickLeft": "Лівий Стік", + "StickRight": "Правий Стік", + "UserProfilesSelectedUserProfile": "Вибраний профіль користувача:", + "UserProfilesSaveProfileName": "Зберегти ім'я профілю", + "UserProfilesChangeProfileImage": "Змінити зображення профілю", + "UserProfilesAvailableUserProfiles": "Доступні профілі користувачів:", + "UserProfilesAddNewProfile": "Створити профіль", + "UserProfilesDelete": "Видалити", + "UserProfilesClose": "Закрити", + "ProfileNameSelectionWatermark": "Оберіть псевдонім", + "ProfileImageSelectionTitle": "Вибір зображення профілю", + "ProfileImageSelectionHeader": "Виберіть зображення профілю", + "ProfileImageSelectionNote": "Ви можете імпортувати власне зображення профілю або вибрати аватар із мікропрограми системи", + "ProfileImageSelectionImportImage": "Імпорт файлу зображення", + "ProfileImageSelectionSelectAvatar": "Виберіть аватар прошивки ", + "InputDialogTitle": "Діалог введення", + "InputDialogOk": "Гаразд", + "InputDialogCancel": "Скасувати", + "InputDialogCancelling": "Скасування", + "InputDialogClose": "Закрити", + "InputDialogAddNewProfileTitle": "Виберіть ім'я профілю", + "InputDialogAddNewProfileHeader": "Будь ласка, введіть ім'я профілю", + "InputDialogAddNewProfileSubtext": "(Макс. довжина: {0})", + "AvatarChoose": "Вибрати", + "AvatarSetBackgroundColor": "Встановити колір фону", + "AvatarClose": "Закрити", + "ControllerSettingsLoadProfileToolTip": "Завантажити профіль", + "ControllerSettingsViewProfileToolTip": "Показати профіль", + "ControllerSettingsAddProfileToolTip": "Додати профіль", + "ControllerSettingsRemoveProfileToolTip": "Видалити профіль", + "ControllerSettingsSaveProfileToolTip": "Зберегти профіль", + "MenuBarFileToolsTakeScreenshot": "Зробити знімок екрана", + "MenuBarFileToolsHideUi": "Сховати інтерфейс", + "GameListContextMenuRunApplication": "Запустити додаток", + "GameListContextMenuToggleFavorite": "Перемкнути вибране", + "GameListContextMenuToggleFavoriteToolTip": "Перемкнути улюблений статус гри", + "SettingsTabGeneralTheme": "Тема:", + "SettingsTabGeneralThemeAuto": "Авто.", + "SettingsTabGeneralThemeDark": "Темна", + "SettingsTabGeneralThemeLight": "Світла", + "ControllerSettingsConfigureGeneral": "Налаштування", + "ControllerSettingsRumble": "Вібрація", + "ControllerSettingsRumbleStrongMultiplier": "Множник сильної вібрації", + "ControllerSettingsRumbleWeakMultiplier": "Множник слабкої вібрації", + "DialogMessageSaveNotAvailableMessage": "Немає збережених даних для {0} [{1:x16}]", + "DialogMessageSaveNotAvailableCreateSaveMessage": "Хочете створити дані збереження для цієї гри?", + "DialogConfirmationTitle": "Ryujinx - Підтвердження", + "DialogUpdaterTitle": "Ryujinx - Програма оновлення", + "DialogErrorTitle": "Ryujinx - Помилка", + "DialogWarningTitle": "Ryujinx - Попередження", + "DialogExitTitle": "Ryujinx - Вихід", + "DialogErrorMessage": "У Ryujinx сталася помилка", + "DialogExitMessage": "Ви впевнені, що бажаєте закрити Ryujinx?", + "DialogExitSubMessage": "Усі незбережені дані буде втрачено!", + "DialogMessageCreateSaveErrorMessage": "Під час створення вказаних даних збереження сталася помилка: {0}", + "DialogMessageFindSaveErrorMessage": "Під час пошуку вказаних даних збереження сталася помилка: {0}", + "FolderDialogExtractTitle": "Виберіть теку для видобування", + "DialogNcaExtractionMessage": "Видобування розділу {0} з {1}...", + "DialogNcaExtractionTitle": "Екстрактор розділів NCA", + "DialogNcaExtractionMainNcaNotFoundErrorMessage": "Помилка видобування. Основний NCA не був присутній у вибраному файлі.", + "DialogNcaExtractionCheckLogErrorMessage": "Помилка видобування. Прочитайте файл журналу для отримання додаткової інформації.", + "DialogNcaExtractionSuccessMessage": "Видобування успішно завершено.", + "DialogUpdaterConvertFailedMessage": "Не вдалося конвертувати поточну версію Ryujinx.", + "DialogUpdaterCancelUpdateMessage": "Скасування оновлення!", + "DialogUpdaterAlreadyOnLatestVersionMessage": "Ви вже використовуєте останню версію Ryujinx!", + "DialogUpdaterFailedToGetVersionMessage": "Під час спроби отримати інформацію про випуск із GitHub Release сталася помилка. Це може бути спричинено, якщо новий випуск компілюється GitHub Actions. Повторіть спробу через кілька хвилин.", + "DialogUpdaterConvertFailedGithubMessage": "Не вдалося конвертувати отриману версію Ryujinx із випуску Github.", + "DialogUpdaterDownloadingMessage": "Завантаження оновлення...", + "DialogUpdaterExtractionMessage": "Видобування оновлення...", + "DialogUpdaterRenamingMessage": "Перейменування оновлення...", + "DialogUpdaterAddingFilesMessage": "Додавання нового оновлення...", + "DialogUpdaterShowChangelogMessage": "Показати список змін", + "DialogUpdaterCompleteMessage": "Оновлення завершено!", + "DialogUpdaterRestartMessage": "Перезапустити Ryujinx зараз?", + "DialogUpdaterNoInternetMessage": "Ви не підключені до Інтернету!", + "DialogUpdaterNoInternetSubMessage": "Будь ласка, переконайтеся, що у вас є робоче підключення до Інтернету!", + "DialogUpdaterDirtyBuildMessage": "Ви не можете оновити брудну збірку Ryujinx!", + "DialogUpdaterDirtyBuildSubMessage": "Будь ласка, завантажте Ryujinx на https://ryujinx.app/download, якщо ви шукаєте підтримувану версію.", + "DialogRestartRequiredMessage": "Потрібен перезапуск", + "DialogThemeRestartMessage": "Тему збережено. Щоб застосувати тему, потрібен перезапуск.", + "DialogThemeRestartSubMessage": "Ви хочете перезапустити", + "DialogFirmwareInstallEmbeddedMessage": "Бажаєте встановити прошивку, вбудовану в цю гру? (Прошивка {0})", + "DialogFirmwareInstallEmbeddedSuccessMessage": "Встановлену прошивку не знайдено, але Ryujinx вдалося встановити прошивку {0} з наданої гри.\nТепер запуститься емулятор.", + "DialogFirmwareNoFirmwareInstalledMessage": "Прошивка не встановлена", + "DialogFirmwareInstalledMessage": "Встановлено прошивку {0}", + "DialogInstallFileTypesSuccessMessage": "Успішно встановлено типи файлів!", + "DialogInstallFileTypesErrorMessage": "Не вдалося встановити типи файлів.", + "DialogUninstallFileTypesSuccessMessage": "Успішно видалено типи файлів!", + "DialogUninstallFileTypesErrorMessage": "Не вдалося видалити типи файлів.", + "DialogOpenSettingsWindowLabel": "Відкрити вікно налаштувань", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", + "DialogControllerAppletTitle": "Аплет контролера", + "DialogMessageDialogErrorExceptionMessage": "Помилка показу діалогового вікна повідомлення: {0}", + "DialogSoftwareKeyboardErrorExceptionMessage": "Помилка показу програмної клавіатури: {0}", + "DialogErrorAppletErrorExceptionMessage": "Помилка показу діалогового вікна ErrorApplet: {0}", + "DialogUserErrorDialogMessage": "{0}: {1}", + "DialogUserErrorDialogInfoMessage": "\nДля отримання додаткової інформації про те, як виправити цю помилку, дотримуйтесь нашого посібника з налаштування.", + "DialogUserErrorDialogTitle": "Помилка Ryujinx ({0})", + "DialogAmiiboApiTitle": "Amiibo API", + "DialogAmiiboApiFailFetchMessage": "Під час отримання інформації з API сталася помилка.", + "DialogAmiiboApiConnectErrorMessage": "Неможливо підключитися до сервера Amiibo API. Можливо, служба не працює або вам потрібно перевірити, чи є підключення до Інтернету.", + "DialogProfileInvalidProfileErrorMessage": "Профіль {0} несумісний із поточною системою конфігурації вводу.", + "DialogProfileDefaultProfileOverwriteErrorMessage": "Стандартний профіль не можна перезаписати", + "DialogProfileDeleteProfileTitle": "Видалення профілю", + "DialogProfileDeleteProfileMessage": "Цю дію неможливо скасувати. Ви впевнені, що бажаєте продовжити?", + "DialogWarning": "Увага", + "DialogPPTCDeletionMessage": "Ви збираєтеся видалити кеш PPTC для:\n\n{0}\n\nВи впевнені, що бажаєте продовжити?", + "DialogPPTCDeletionErrorMessage": "Помилка очищення кешу PPTC на {0}: {1}", + "DialogShaderDeletionMessage": "Ви збираєтеся видалити кеш шейдерів для:\n\n{0}\n\nВи впевнені, що бажаєте продовжити?", + "DialogShaderDeletionErrorMessage": "Помилка очищення кешу шейдерів на {0}: {1}", + "DialogRyujinxErrorMessage": "У Ryujinx сталася помилка", + "DialogInvalidTitleIdErrorMessage": "Помилка інтерфейсу: вибрана гра не мала дійсного ідентифікатора назви", + "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Дійсна прошивка системи не знайдена в {0}.", + "DialogFirmwareInstallerFirmwareInstallTitle": "Встановити прошивку {0}", + "DialogFirmwareInstallerFirmwareInstallMessage": "Буде встановлено версію системи {0}.", + "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nЦе замінить поточну версію системи {0}.", + "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nВи хочете продовжити?", + "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Встановлення прошивки...", + "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Версію системи {0} успішно встановлено.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Встановлення Ключів", + "DialogKeysInstallerKeysInstallMessage": "Новий файл Ключів буде встановлено", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nЦе замінить собою поточні файли Ключів.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nВи хочете продовжити?", + "DialogKeysInstallerKeysInstallWaitMessage": "Встановлення Ключів...", + "DialogKeysInstallerKeysInstallSuccessMessage": "Нові ключі встановлено.", + "DialogUserProfileDeletionWarningMessage": "Якщо вибраний профіль буде видалено, інші профілі не відкриватимуться", + "DialogUserProfileDeletionConfirmMessage": "Ви хочете видалити вибраний профіль", + "DialogUserProfileUnsavedChangesTitle": "Увага — Незбережені зміни", + "DialogUserProfileUnsavedChangesMessage": "Ви зробили зміни у цьому профілю користувача які не було збережено.", + "DialogUserProfileUnsavedChangesSubMessage": "Бажаєте скасувати зміни?", + "DialogControllerSettingsModifiedConfirmMessage": "Поточні налаштування контролера оновлено.", + "DialogControllerSettingsModifiedConfirmSubMessage": "Ви хочете зберегти?", + "DialogLoadFileErrorMessage": "{0}. Файл з помилкою: {1}", + "DialogModAlreadyExistsMessage": "Модифікація вже існує", + "DialogModInvalidMessage": "Вказаний каталог не містить модифікації!", + "DialogModDeleteNoParentMessage": "Не видалено: Не знайдено батьківський каталог для модифікації \"{0}\"!", + "DialogDlcNoDlcErrorMessage": "Зазначений файл не містить DLC для вибраного заголовку!", + "DialogPerformanceCheckLoggingEnabledMessage": "Ви увімкнули журнал налагодження, призначений лише для розробників.", + "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальної продуктивності рекомендується вимкнути ведення журналу налагодження. Ви хочете вимкнути ведення журналу налагодження зараз?", + "DialogPerformanceCheckShaderDumpEnabledMessage": "Ви увімкнули скидання шейдерів, призначений лише для розробників.", + "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Для оптимальної продуктивності рекомендується вимкнути скидання шейдерів. Ви хочете вимкнути скидання шейдерів зараз?", + "DialogLoadAppGameAlreadyLoadedMessage": "Гру вже завантажено", + "DialogLoadAppGameAlreadyLoadedSubMessage": "Зупиніть емуляцію або закрийте емулятор перед запуском іншої гри.", + "DialogUpdateAddUpdateErrorMessage": "Зазначений файл не містить оновлення для вибраного заголовка!", + "DialogSettingsBackendThreadingWarningTitle": "Попередження - потокове керування сервером", + "DialogSettingsBackendThreadingWarningMessage": "Ryujinx потрібно перезапустити після зміни цього параметра, щоб він застосовувався повністю. Залежно від вашої платформи вам може знадобитися вручну вимкнути власну багатопотоковість драйвера під час використання Ryujinx.", + "DialogModManagerDeletionWarningMessage": "Ви збираєтесь видалити модифікацію: {0}\n\nВи дійсно бажаєте продовжити?", + "DialogModManagerDeletionAllWarningMessage": "Ви збираєтесь видалити всі модифікації для цього Додатка.\n\nВи дійсно бажаєте продовжити?", + "SettingsTabGraphicsFeaturesOptions": "Особливості", + "SettingsTabGraphicsBackendMultithreading": "Багатопотоковість графічного сервера:", + "CommonAuto": "Авто", + "CommonOff": "Вимкнути", + "CommonOn": "Увімкнути", + "InputDialogYes": "Так", + "InputDialogNo": "Ні", + "DialogProfileInvalidProfileNameErrorMessage": "Ім'я файлу містить неприпустимі символи. Будь ласка, спробуйте ще раз.", + "MenuBarOptionsPauseEmulation": "Пауза", + "MenuBarOptionsResumeEmulation": "Продовжити", + "AboutUrlTooltipMessage": "Натисніть, щоб відкрити сайт Ryujinx у браузері за замовчування.", + "AboutDisclaimerMessage": "Ryujinx жодним чином не пов’язаний з Nintendo™,\nчи будь-яким із їхніх партнерів.", + "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) використовується в нашій емуляції Amiibo.", + "AboutGithubUrlTooltipMessage": "Натисніть, щоб відкрити сторінку GitHub Ryujinx у браузері за замовчуванням.", + "AboutDiscordUrlTooltipMessage": "Натисніть, щоб відкрити запрошення на сервер Discord Ryujinx у браузері за замовчуванням.", + "AboutRyujinxAboutTitle": "Про програму:", + "AboutRyujinxAboutContent": "Ryujinx — це емулятор для Nintendo Switch™.\nОтримуйте всі останні новини в нашому Discord.\nРозробники, які хочуть зробити внесок, можуть дізнатися більше на нашому GitHub або в Discord.", + "AboutRyujinxMaintainersTitle": "Підтримується:", + "AboutRyujinxFormerMaintainersTitle": "Минулі розробники:", + "AboutRyujinxMaintainersContentTooltipMessage": "Натисніть, щоб відкрити сторінку співавторів у вашому браузері за замовчування.", + "AmiiboSeriesLabel": "Серія Amiibo", + "AmiiboCharacterLabel": "Персонаж", + "AmiiboScanButtonLabel": "Сканувати", + "AmiiboOptionsShowAllLabel": "Показати всі Amiibo", + "AmiiboOptionsUsRandomTagLabel": "Хитрість: Використовувати випадковий тег Uuid", + "DlcManagerTableHeadingEnabledLabel": "Увімкнено", + "DlcManagerTableHeadingTitleIdLabel": "ID заголовка", + "DlcManagerTableHeadingContainerPathLabel": "Шлях до контейнеру", + "DlcManagerTableHeadingFullPathLabel": "Повний шлях", + "DlcManagerRemoveAllButton": "Видалити все", + "DlcManagerEnableAllButton": "Увімкнути всі", + "DlcManagerDisableAllButton": "Вимкнути всі", + "ModManagerDeleteAllButton": "Видалити все", + "MenuBarOptionsChangeLanguage": "Змінити мову", + "MenuBarShowFileTypes": "Показати типи файлів", + "CommonSort": "Сортувати", + "CommonShowNames": "Показати назви", + "CommonFavorite": "Вибрані", + "OrderAscending": "За зростанням", + "OrderDescending": "За спаданням", + "SettingsTabGraphicsFeatures": "Функції та вдосконалення", + "ErrorWindowTitle": "Вікно помилок", + "ToggleDiscordTooltip": "Виберіть, чи відображати Ryujinx у вашій «поточній грі» в Discord", + "AddGameDirBoxTooltip": "Введіть каталог ігор, щоб додати до списку", + "AddGameDirTooltip": "Додати каталог гри до списку", + "RemoveGameDirTooltip": "Видалити вибраний каталог гри", + "AddAutoloadDirBoxTooltip": "Введіть шлях автозавантаження для додавання до списку", + "AddAutoloadDirTooltip": "Додайте шлях автозавантаження для додавання до списку", + "RemoveAutoloadDirTooltip": "Видалити вибраний каталог автозавантаження", + "CustomThemeCheckTooltip": "Використовуйте користувацьку тему Avalonia для графічного інтерфейсу, щоб змінити вигляд меню емулятора", + "CustomThemePathTooltip": "Шлях до користувацької теми графічного інтерфейсу", + "CustomThemeBrowseTooltip": "Огляд користувацької теми графічного інтерфейсу", + "DockModeToggleTooltip": "У режимі док-станції емульована система веде себе як приєднаний Nintendo Switch. Це покращує точність графіки в більшості ігор. І навпаки, вимкнення цього призведе до того, що емульована система поводитиметься як портативний комутатор Nintendo, погіршуючи якість графіки.\n\nНалаштуйте елементи керування для гравця 1, якщо плануєте використовувати режим док-станції; налаштуйте ручні елементи керування, якщо плануєте використовувати портативний режим.\n\nЗалиште увімкненим, якщо не впевнені.", + "DirectKeyboardTooltip": "Підтримка прямого доступу до клавіатури (HID). Надає іграм доступ до клавіатури для вводу тексту.\n\nПрацює тільки з іграми, які підтримують клавіатуру на обладнанні Switch.\n\nЗалиште вимкненим, якщо не впевнені.", + "DirectMouseTooltip": "Підтримка прямого доступу до миші (HID). Надає іграм доступ до миші, як пристрій вказування.\n\nПрацює тільки з іграми, які підтримують мишу на обладнанні Switch, їх небагато.\n\nФункціонал сенсорного екрана може не працювати, якщо функція ввімкнена.\n\nЗалиште вимкненим, якщо не впевнені.", + "RegionTooltip": "Змінити регіон системи", + "LanguageTooltip": "Змінити мову системи", + "TimezoneTooltip": "Змінити часовий пояс системи", + "TimeTooltip": "Змінити час системи", + "VSyncToggleTooltip": "Емульована вертикальна синхронізація консолі. По суті, обмежувач кадрів для більшості ігор; його вимкнення може призвести до того, що ігри працюватимуть на вищій швидкості, екрани завантаження триватимуть довше чи зупинятимуться.\n\nМожна перемикати в грі гарячою клавішею (За умовчанням F1). Якщо ви плануєте вимкнути функцію, рекомендуємо зробити це через гарячу клавішу.\n\nЗалиште увімкненим, якщо не впевнені.", + "PptcToggleTooltip": "Зберігає перекладені функції JIT, щоб їх не потрібно було перекладати кожного разу, коли гра завантажується.\n\nЗменшує заїкання та значно прискорює час завантаження після першого завантаження гри.\n\nЗалиште увімкненим, якщо не впевнені.", + "LowPowerPptcToggleTooltip": "Завантажувати PPTC використовуючи третину від кількості ядер.", + "FsIntegrityToggleTooltip": "Перевіряє наявність пошкоджених файлів під час завантаження гри, і якщо виявлено пошкоджені файли, показує помилку хешу в журналі.\n\nНе впливає на продуктивність і призначений для усунення несправностей.\n\nЗалиште увімкненим, якщо не впевнені.", + "AudioBackendTooltip": "Змінює серверну частину, яка використовується для відтворення аудіо.\n\nSDL2 є кращим, тоді як OpenAL і SoundIO використовуються як резервні варіанти. Dummy не матиме звуку.\n\nВстановіть SDL2, якщо не впевнені.", + "MemoryManagerTooltip": "Змінює спосіб відображення та доступу до гостьової пам’яті. Значно впливає на продуктивність емульованого ЦП.\n\nВстановіть «Неперевірений хост», якщо не впевнені.", + "MemoryManagerSoftwareTooltip": "Використовує програмну таблицю сторінок для перекладу адрес. Найвища точність, але найповільніша продуктивність.", + "MemoryManagerHostTooltip": "Пряме відображення пам'яті в адресному просторі хосту. Набагато швидша компіляція та виконання JIT.", + "MemoryManagerUnsafeTooltip": "Пряме відображення пам’яті, але не маскує адресу в гостьовому адресному просторі перед доступом. Швидше, але ціною безпеки. Гостьова програма може отримати доступ до пам’яті з будь-якого місця в Ryujinx, тому запускайте в цьому режимі лише програми, яким ви довіряєте.", + "UseHypervisorTooltip": "Використання гіпервізор замість JIT. Значно покращує продуктивність, коли доступний, але може бути нестабільним у поточному стані.", + "DRamTooltip": "Використовує альтернативний макет MemoryMode для імітації моделі розробки Switch.\n\nЦе корисно лише для пакетів текстур з вищою роздільною здатністю або модифікацій із роздільною здатністю 4K. НЕ покращує продуктивність.\n\nЗалиште вимкненим, якщо не впевнені.", + "IgnoreMissingServicesTooltip": "Ігнорує нереалізовані служби Horizon OS. Це може допомогти в обході збоїв під час завантаження певних ігор.\n\nЗалиште вимкненим, якщо не впевнені.", + "IgnoreAppletTooltip": "Зовнішнє діалогове вікно \"Аплет контролера\" не з’являтиметься, якщо геймпад буде від’єднано під час гри. Не буде запиту закрити діалогове вікно чи налаштувати новий контролер. Після повторного підключення раніше від’єднаного контролера гра автоматично відновиться.", + "GraphicsBackendThreadingTooltip": "Виконує команди графічного сервера в другому потоці.\n\nПрискорює компіляцію шейдерів, зменшує затримки та покращує продуктивність драйверів GPU без власної підтримки багатопоточності. Трохи краща продуктивність на драйверах з багатопотоковістю.\nВстановіть значення «Авто», якщо не впевнені", + "GalThreadingTooltip": "Виконує команди графічного сервера в другому потоці.\n\nПрискорює компіляцію шейдерів, зменшує затримки та покращує продуктивність драйверів GPU без власної підтримки багатопоточності. Трохи краща продуктивність на драйверах з багатопотоковістю.\n\nВстановіть значення «Авто», якщо не впевнені.", + "ShaderCacheToggleTooltip": "Зберігає кеш дискового шейдера, що зменшує затримки під час наступних запусків.\n\nЗалиште увімкненим, якщо не впевнені.", + "ResolutionScaleTooltip": "Множить роздільну здатність гри.\n\nДеякі ігри можуть не працювати з цією функцією, і виглядатимуть піксельними; для цих ігор треба знайти модифікації, що зупиняють згладжування або підвищують роздільну здатність. Для останніх модифікацій, вибирайте \"Native\".\n\nЦей параметр можна міняти коли гра запущена кліком на \"Застосувати\"; ви можете перемістити вікно налаштувань і поекспериментувати з видом гри.\n\nМайте на увазі, що 4x це занадто для будь-якого комп'ютера.", + "ResolutionScaleEntryTooltip": "Масштаб роздільної здатності з плаваючою комою, наприклад 1,5. Не інтегральні масштаби, швидше за все, спричинять проблеми або збій.", + "AnisotropyTooltip": "Рівень анізотропної фільтрації. Встановіть на «Авто», щоб використовувати значення, яке вимагає гра.", + "AspectRatioTooltip": "Співвідношення сторін застосовано до вікна рендера.\n\nМіняйте тільки, якщо використовуєте модифікацію співвідношення сторін для гри, інакше графіка буде розтягнута.\n\nЗалиште на \"16:9\", якщо не впевнені.", + "ShaderDumpPathTooltip": "Шлях скидання графічних шейдерів", + "FileLogTooltip": "Зберігає журнал консолі у файл журналу на диску. Не впливає на продуктивність.", + "StubLogTooltip": "Друкує повідомлення журналу-заглушки на консолі. Не впливає на продуктивність.", + "InfoLogTooltip": "Друкує повідомлення інформаційного журналу на консолі. Не впливає на продуктивність.", + "WarnLogTooltip": "Друкує повідомлення журналу попереджень у консолі. Не впливає на продуктивність.", + "ErrorLogTooltip": "Друкує повідомлення журналу помилок у консолі. Не впливає на продуктивність.", + "TraceLogTooltip": "Друкує повідомлення журналу трасування на консолі. Не впливає на продуктивність.", + "GuestLogTooltip": "Друкує повідомлення журналу гостей у консолі. Не впливає на продуктивність.", + "FileAccessLogTooltip": "Друкує повідомлення журналу доступу до файлів у консолі.", + "FSAccessLogModeTooltip": "Вмикає виведення журналу доступу до FS на консоль. Можливі режими 0-3", + "DeveloperOptionTooltip": "Використовуйте з обережністю", + "OpenGlLogLevel": "Потрібно увімкнути відповідні рівні журналу", + "DebugLogTooltip": "Друкує повідомлення журналу налагодження на консолі.\n\nВикористовуйте це лише за спеціальною вказівкою співробітника, оскільки це ускладнить читання журналів і погіршить роботу емулятора.", + "LoadApplicationFileTooltip": "Відкриває файловий провідник, щоб вибрати для завантаження сумісний файл Switch", + "LoadApplicationFolderTooltip": "Відкриває файловий провідник, щоб вибрати сумісну з комутатором розпаковану програму для завантаження", + "LoadDlcFromFolderTooltip": "Відкрийте провідник файлів, щоб вибрати одну або кілька папок для масового завантаження DLC", + "LoadTitleUpdatesFromFolderTooltip": "Відкрийте провідник файлів, щоб вибрати одну або кілька папок для масового завантаження оновлень заголовків", + "OpenRyujinxFolderTooltip": "Відкриває теку файлової системи Ryujinx", + "OpenRyujinxLogsTooltip": "Відкриває теку, куди записуються журнали", + "ExitTooltip": "Виходить з Ryujinx", + "OpenSettingsTooltip": "Відкриває вікно налаштувань", + "OpenProfileManagerTooltip": "Відкриває вікно диспетчера профілів користувачів", + "StopEmulationTooltip": "Зупиняє емуляцію поточної гри та повертається до вибору гри", + "CheckUpdatesTooltip": "Перевіряє наявність оновлень для Ryujinx", + "OpenAboutTooltip": "Відкриває вікно «Про програму».", + "GridSize": "Розмір сітки", + "GridSizeTooltip": "Змінити розмір елементів сітки", + "SettingsTabSystemSystemLanguageBrazilianPortuguese": "Португальська (Бразилія)", + "AboutRyujinxContributorsButtonHeader": "Переглянути всіх співавторів", + "SettingsTabSystemAudioVolume": "Гучність: ", + "AudioVolumeTooltip": "Змінити гучність звуку", + "SettingsTabSystemEnableInternetAccess": "Гостьовий доступ до Інтернету/режим LAN", + "EnableInternetAccessTooltip": "Дозволяє емульованій програмі підключатися до Інтернету.\n\nІгри з режимом локальної мережі можуть підключатися одна до одної, якщо це увімкнено, і системи підключені до однієї точки доступу. Сюди входять і справжні консолі.\n\nНЕ дозволяє підключатися до серверів Nintendo. Може призвести до збою в деяких іграх, які намагаються підключитися до Інтернету.\n\nЗалиште вимкненим, якщо не впевнені.", + "GameListContextMenuManageCheatToolTip": "Керування читами", + "GameListContextMenuManageCheat": "Керування читами", + "GameListContextMenuManageModToolTip": "Керування модами", + "GameListContextMenuManageMod": "Керування модами", + "ControllerSettingsStickRange": "Діапазон:", + "DialogStopEmulationTitle": "Ryujinx - Зупинити емуляцію", + "DialogStopEmulationMessage": "Ви впевнені, що хочете зупинити емуляцію?", + "SettingsTabCpu": "ЦП", + "SettingsTabAudio": "Аудіо", + "SettingsTabNetwork": "Мережа", + "SettingsTabNetworkConnection": "Підключення до мережі", + "SettingsTabCpuCache": "Кеш ЦП", + "SettingsTabCpuMemory": "Пам'ять ЦП", + "UpdaterDisabledWarningTitle": "Програму оновлення вимкнено!", + "ControllerSettingsRotate90": "Повернути на 90° за годинниковою стрілкою", + "IconSize": "Розмір значка", + "IconSizeTooltip": "Змінити розмір значків гри", + "MenuBarOptionsShowConsole": "Показати консоль", + "ShaderCachePurgeError": "Помилка очищення кешу шейдера {0}: {1}", + "UserErrorNoKeys": "Ключі не знайдено", + "UserErrorNoFirmware": "Прошивка не знайдена", + "UserErrorFirmwareParsingFailed": "Помилка аналізу прошивки", + "UserErrorApplicationNotFound": "Додаток не знайдено", + "UserErrorUnknown": "Невідома помилка", + "UserErrorUndefined": "Невизначена помилка", + "UserErrorNoKeysDescription": "Ryujinx не вдалося знайти ваш файл «prod.keys».", + "UserErrorNoFirmwareDescription": "Ryujinx не вдалося знайти встановлену прошивку", + "UserErrorFirmwareParsingFailedDescription": "Ryujinx не вдалося проаналізувати прошивку. Зазвичай це спричинено застарілими ключами.", + "UserErrorApplicationNotFoundDescription": "Ryujinx не вдалося знайти дійсний додаток за вказаним шляхом", + "UserErrorUnknownDescription": "Сталася невідома помилка!", + "UserErrorUndefinedDescription": "Сталася невизначена помилка! Цього не повинно статися, зверніться до розробника!", + "OpenSetupGuideMessage": "Відкрити посібник із налаштування", + "NoUpdate": "Немає оновлень", + "TitleUpdateVersionLabel": "Версія {0} - {1}", + "TitleBundledUpdateVersionLabel": "Комплектні: Версія {0}", + "TitleBundledDlcLabel": "Комплектні:", + "TitleXCIStatusPartialLabel": "Часткові", + "TitleXCIStatusTrimmableLabel": "Необрізані", + "TitleXCIStatusUntrimmableLabel": "Обрізані", + "TitleXCIStatusFailedLabel": "(Невдача)", + "TitleXCICanSaveLabel": "Зберегти {0:n0} Мб", + "TitleXCISavingLabel": "Збережено {0:n0} Мб", + "RyujinxInfo": "Ryujin x - Інформація", + "RyujinxConfirm": "Ryujinx - Підтвердження", + "FileDialogAllTypes": "Всі типи", + "Never": "Ніколи", + "SwkbdMinCharacters": "Мінімальна кількість символів: {0}", + "SwkbdMinRangeCharacters": "Має бути {0}-{1} символів", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Вкажіть Ваше нове ім'я Amiibo", + "CabinetScanDialog": "Будь ласка, проскануйте Ваш Amiibo.", + "SoftwareKeyboard": "Програмна клавіатура", + "SoftwareKeyboardModeNumeric": "Повинно бути лише 0-9 або “.”", + "SoftwareKeyboardModeAlphabet": "Повинно бути лише не CJK-символи", + "SoftwareKeyboardModeASCII": "Повинно бути лише ASCII текст", + "ControllerAppletControllers": "Підтримувані контролери:", + "ControllerAppletPlayers": "Гравці:", + "ControllerAppletDescription": "Поточна конфігурація невірна. Відкрийте налаштування та переналаштуйте Ваші дані.", + "ControllerAppletDocked": "Встановлений режим в док-станції. Вимкніть портативні контролери.", + "UpdaterRenaming": "Перейменування старих файлів...", + "UpdaterRenameFailed": "Програмі оновлення не вдалося перейменувати файл: {0}", + "UpdaterAddingFiles": "Додавання нових файлів...", + "UpdaterExtracting": "Видобування оновлення...", + "UpdaterDownloading": "Завантаження оновлення...", + "Docked": "Док-станція", + "Handheld": "Портативний", + "ConnectionError": "Помилка з'єднання.", + "AboutPageDeveloperListMore": "{0} та інші...", + "ApiError": "Помилка API.", + "LoadingHeading": "Завантаження {0}", + "CompilingPPTC": "Компіляція PTC", + "CompilingShaders": "Компіляція шейдерів", + "AllKeyboards": "Всі клавіатури", + "OpenFileDialogTitle": "Виберіть підтримуваний файл для відкриття", + "OpenFolderDialogTitle": "Виберіть теку з розпакованою грою", + "AllSupportedFormats": "Усі підтримувані формати", + "RyujinxUpdater": "Програма оновлення Ryujinx", + "SettingsTabHotkeys": "Гарячі клавіші клавіатури", + "SettingsTabHotkeysToggleVSyncModeHotkey": "Перемкнути VSync режим:", + "SettingsTabHotkeysHotkeys": "Гарячі клавіші клавіатури", + "SettingsTabHotkeysToggleVsyncHotkey": "Увімк/вимк вертикальну синхронізацію:", + "SettingsTabHotkeysScreenshotHotkey": "Знімок екрана:", + "SettingsTabHotkeysShowUiHotkey": "Показати інтерфейс:", + "SettingsTabHotkeysPauseHotkey": "Пауза:", + "SettingsTabHotkeysToggleMuteHotkey": "Вимкнути звук:", + "SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey": "Підвищити користувацьку частоту оновлення", + "SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey": "Понизити користувацьку частоту оновлення", + "ControllerMotionTitle": "Налаштування керування рухом", + "ControllerRumbleTitle": "Налаштування вібрації", + "SettingsSelectThemeFileDialogTitle": "Виберіть файл теми", + "SettingsXamlThemeFile": "Файл теми Xaml", + "AvatarWindowTitle": "Керування обліковими записами - Аватар", + "Amiibo": "Amiibo", + "Unknown": "Невідомо", + "Usage": "Використання", + "Writable": "Можливість запису", + "SelectDlcDialogTitle": "Виберіть файли DLC", + "SelectUpdateDialogTitle": "Виберіть файли оновлення", + "SelectModDialogTitle": "Виберіть теку з модами", + "TrimXCIFileDialogTitle": "Перевірити та Обрізати XCI файл", + "TrimXCIFileDialogPrimaryText": "Ця функція спочатку перевірить вільний простір, а потім обрізатиме файл XCI для економії місця на диску.", + "TrimXCIFileDialogSecondaryText": "Поточний розмір файла: {0:n} MB\nРозмір файлів гри: {1:n} MB\nЕкономія місця: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI файл не потребує обрізання. Перевірте журнали для додаткової інформації", + "TrimXCIFileNoUntrimPossible": "XCI файл не може бути обрізаний. Перевірте журнали для додаткової інформації", + "TrimXCIFileReadOnlyFileCannotFix": "XCI файл Тільки для Читання і не може бути прочитаним. Перевірте журнали додаткової інформації", + "TrimXCIFileFileSizeChanged": "Розмір файлу XCI змінився з моменту сканування. Перевірте, чи не записується файл, та спробуйте знову", + "TrimXCIFileFreeSpaceCheckFailed": "Файл XCI містить дані в зоні вільного простору, тому обрізка небезпечна", + "TrimXCIFileInvalidXCIFile": "XCI Файл містить недійсні дані. Перевірте журнали для додаткової інформації", + "TrimXCIFileFileIOWriteError": "XCI Файл файл не вдалося відкрити для запису. Перевірте журнали для додаткової інформації", + "TrimXCIFileFailedPrimaryText": "Не вдалося обрізати файл XCI", + "TrimXCIFileCancelled": "Операція перервана", + "TrimXCIFileFileUndertermined": "Операція не проводилася", + "UserProfileWindowTitle": "Менеджер профілів користувачів", + "CheatWindowTitle": "Менеджер читів", + "DlcWindowTitle": "Менеджер вмісту для завантаження", + "ModWindowTitle": "Керувати модами для {0} ({1})", + "UpdateWindowTitle": "Менеджер оновлення назв", + "XCITrimmerWindowTitle": "Обрізка XCI Файлів", + "XCITrimmerTitleStatusCount": "{0} з {1} тайтл(ів) обрано", + "XCITrimmerTitleStatusCountWithFilter": "{0} з {1} тайтл(ів) обрано ({2} відображається)", + "XCITrimmerTitleStatusTrimming": "Обрізка {0} тайтл(ів)...", + "XCITrimmerTitleStatusUntrimming": "Необрізаних {0} тайтл(ів)...", + "XCITrimmerTitleStatusFailed": "Невдача", + "XCITrimmerPotentialSavings": "Потенційна економія", + "XCITrimmerActualSavings": "Зекономлено", + "XCITrimmerSavingsMb": "{0:n0} Мб", + "XCITrimmerSelectDisplayed": "Вибрати показане", + "XCITrimmerDeselectDisplayed": "Скасувати вибір показаного", + "XCITrimmerSortName": "Заголовок", + "XCITrimmerSortSaved": "Економія місця", + "XCITrimmerTrim": "Обрізка", + "XCITrimmerUntrim": "Зшивання", + "UpdateWindowUpdateAddedMessage": "{0} нове оновлення додано", + "UpdateWindowBundledContentNotice": "Вбудовані оновлення не можуть бути видалені, лише вимкнені.", + "CheatWindowHeading": "Коди доступні для {0} [{1}]", + "BuildId": "ID збірки:", + "DlcWindowBundledContentNotice": "Вбудований DLC не може бути видаленим, лише вимкненим.", + "DlcWindowHeading": "{0} DLC доступно", + "DlcWindowDlcAddedMessage": "{0} нового завантажувального вмісту додано", + "AutoloadDlcAddedMessage": "{0} нового завантажувального вмісту додано", + "AutoloadDlcRemovedMessage": "{0} відсутнього завантажувального вмісту видалено", + "AutoloadUpdateAddedMessage": "{0} нових оновлень додано", + "AutoloadUpdateRemovedMessage": "{0} відсутніх оновлень видалено", + "ModWindowHeading": "{0} мод(ів)", + "UserProfilesEditProfile": "Редагувати вибране", + "Continue": "Продовжити", + "Cancel": "Скасувати", + "Save": "Зберегти", + "Discard": "Скасувати", + "Paused": "Призупинено", + "UserProfilesSetProfileImage": "Встановити зображення профілю", + "UserProfileEmptyNameError": "Імʼя обовʼязкове", + "UserProfileNoImageError": "Зображення профілю обовʼязкове", + "GameUpdateWindowHeading": "{0} Доступні оновлення для {1} ({2})", + "SettingsTabHotkeysResScaleUpHotkey": "Збільшити роздільність:", + "SettingsTabHotkeysResScaleDownHotkey": "Зменшити роздільність:", + "UserProfilesName": "Імʼя", + "UserProfilesUserId": "ID користувача:", + "SettingsTabGraphicsBackend": "Графічний сервер", + "SettingsTabGraphicsBackendTooltip": "Виберіть backend графіки, що буде використовуватись в емуляторі.\n\n\"Vulkan\" краще для всіх сучасних відеокарт, якщо драйвери вчасно оновлюються. У Vulkan також швидше компілюються шейдери (менше \"заїкання\" зображення) на відеокартах всіх компаній.\n\n\"OpenGL\" може дати кращі результати на старих відеокартах Nvidia, старих відеокартах AMD на Linux, або на відеокартах з маленькою кількістю VRAM, але \"заїкання\" через компіляцію шейдерів будуть частіші.\n\nЯкщо не впевнені, встановіть на \"Vulkan\". Встановіть на \"OpenGL\", якщо Ваша відеокарта не підтримує Vulkan навіть на останніх драйверах.", + "SettingsEnableTextureRecompression": "Увімкнути рекомпресію текстури", + "SettingsEnableTextureRecompressionTooltip": "Стискає текстури ASTC, щоб зменшити використання VRAM.\n\nЦим форматом текстур користуються такі ігри, як Astral Chain, Bayonetta 3, Fire Emblem Engage, Metroid Prime Remastered, Super Mario Bros. Wonder і The Legend of Zelda: Tears of the Kingdom.\n\nЦі ігри, скоріше всього крашнуться на відеокартах з розміром VRAM в 4 Гб і менше.\n\nВмикайте тільки якщо у Вас закінчується VRAM на цих іграх. Залиште на \"Вимкнути\", якщо не впевнені.", + "SettingsTabGraphicsPreferredGpu": "Бажаний GPU", + "SettingsTabGraphicsPreferredGpuTooltip": "Виберіть відеокарту, яка використовуватиметься з графічним сервером Vulkan.\n\nНе впливає на графічний процесор, який використовуватиме OpenGL.\n\nВстановіть графічний процесор, позначений як «dGPU», якщо не впевнені. Якщо такого немає, не чіпайте.", + "SettingsAppRequiredRestartMessage": "Необхідно перезапустити Ryujinx", + "SettingsGpuBackendRestartMessage": "Налаштування графічного сервера або GPU було змінено. Для цього знадобиться перезапуск", + "SettingsGpuBackendRestartSubMessage": "Бажаєте перезапустити зараз?", + "RyujinxUpdaterMessage": "Бажаєте оновити Ryujinx до останньої версії?", + "SettingsTabHotkeysVolumeUpHotkey": "Збільшити гучність:", + "SettingsTabHotkeysVolumeDownHotkey": "Зменшити гучність:", + "SettingsEnableMacroHLE": "Увімкнути макрос HLE", + "SettingsEnableMacroHLETooltip": "Високорівнева емуляція коду макросу GPU.\n\nПокращує продуктивність, але може викликати графічні збої в деяких іграх.\n\nЗалиште увімкненим, якщо не впевнені.", + "SettingsEnableColorSpacePassthrough": "Наскрізний колірний простір", + "SettingsEnableColorSpacePassthroughTooltip": "Дозволяє серверу Vulkan передавати інформацію про колір без вказівки колірного простору. Для користувачів з екранами з широкою гамою це може призвести до більш яскравих кольорів, але шляхом втрати коректності передачі кольору.", + "VolumeShort": "Гуч.", + "UserProfilesManageSaves": "Керувати збереженнями", + "DeleteUserSave": "Ви хочете видалити збереження користувача для цієї гри?", + "IrreversibleActionNote": "Цю дію не можна скасувати.", + "SaveManagerHeading": "Керувати збереженнями для {0}", + "SaveManagerTitle": "Менеджер збереження", + "Name": "Назва", + "Size": "Розмір", + "Search": "Пошук", + "UserProfilesRecoverLostAccounts": "Відновлення профілів", + "Recover": "Відновити", + "UserProfilesRecoverHeading": "Знайдено збереження для наступних облікових записів", + "UserProfilesRecoverEmptyList": "Немає профілів для відновлення", + "GraphicsAATooltip": "Застосовує згладження до рендера гри.\n\nFXAA розмиє більшість зображення, а SMAA спробує знайти нерівні краї та згладити їх.\n\nНе рекомендується використовувати разом з фільтром масштабування FSR.\n\nЦю опцію можна міняти коли гра запущена кліком на \"Застосувати; ви можете відсунути вікно налаштувань і поекспериментувати з видом гри.\n\nЗалиште на \"Немає\", якщо не впевнені.", + "GraphicsAALabel": "Згладжування:", + "GraphicsScalingFilterLabel": "Фільтр масштабування:", + "GraphicsScalingFilterTooltip": "Виберіть фільтр масштабування, що використається при збільшенні роздільної здатності.\n\n\"Білінійний\" добре виглядає в 3D іграх, і хороше налаштування за умовчуванням.\n\n\"Найближчий\" рекомендується для ігор з піксель-артом.\n\n\"FSR 1.0\" - це просто фільтр різкості, не рекомендується використовувати разом з FXAA або SMAA.\n\nЦю опцію можна міняти коли гра запущена кліком на \"Застосувати; ви можете відсунути вікно налаштувань і поекспериментувати з видом гри.\n\nЗалиште на \"Білінійний\", якщо не впевнені.", + "GraphicsScalingFilterBilinear": "Білінійний", + "GraphicsScalingFilterNearest": "Найближчий", + "GraphicsScalingFilterFsr": "FSR", + "GraphicsScalingFilterArea": "Area", + "GraphicsScalingFilterLevelLabel": "Рівень", + "GraphicsScalingFilterLevelTooltip": "Встановити рівень різкості в FSR 1.0. Чим вище - тим різкіше.", + "SmaaLow": "SMAA Низький", + "SmaaMedium": "SMAA Середній", + "SmaaHigh": "SMAA Високий", + "SmaaUltra": "SMAA Ультра", + "UserEditorTitle": "Редагувати користувача", + "UserEditorTitleCreate": "Створити користувача", + "SettingsTabNetworkInterface": "Мережевий інтерфейс:", + "NetworkInterfaceTooltip": "Мережевий інтерфейс, що використовується для LAN/LDN.\n\nРазом з VPN або XLink Kai, і грою що підтримує LAN, може імітувати з'єднання в однаковій мережі через Інтернет.", + "NetworkInterfaceDefault": "Стандартний", + "PackagingShaders": "Пакування шейдерів", + "AboutChangelogButton": "Переглянути журнал змін на GitHub", + "AboutChangelogButtonTooltipMessage": "Клацніть, щоб відкрити журнал змін для цієї версії у стандартному браузері.", + "SettingsTabNetworkMultiplayer": "Мережева гра", + "MultiplayerMode": "Режим:", + "MultiplayerModeTooltip": "Змінити LDN мультиплеєру.\n\nLdnMitm змінить функціонал бездротової/локальної гри в іграх, щоб вони працювали так, ніби це LAN, що дозволяє локальні підключення в тій самій мережі з іншими екземплярами Ryujinx та хакнутими консолями Nintendo Switch, які мають встановлений модуль ldn_mitm.\n\nМультиплеєр вимагає, щоб усі гравці були на одній і тій же версії гри (наприклад Super Smash Bros. Ultimate v13.0.1 не зможе під'єднатися до v13.0.0).\n\nЗалиште на \"Вимкнено\", якщо не впевнені, ", + "MultiplayerModeDisabled": "Вимкнено", + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Вимкнути хостинг P2P мережі (може збільшити затримку)", + "MultiplayerDisableP2PTooltip": "Вимкнути хостинг P2P мережі, піри будуть підключатися через майстер-сервер замість прямого з'єднання з вами.", + "LdnPassphrase": "Мережевий пароль:", + "LdnPassphraseTooltip": "Ви зможете бачити лише ті ігри, які мають такий самий пароль, як і у вас.", + "LdnPassphraseInputTooltip": "Введіть пароль у форматі Ryujinx-<8 символів>. Ви зможете бачити лише ті ігри, які мають такий самий пароль, як і у вас.", + "LdnPassphraseInputPublic": "(публічний)", + "GenLdnPass": "Згенерувати випадкову", + "GenLdnPassTooltip": "Генерує новий пароль, яким можна поділитися з іншими гравцями.", + "ClearLdnPass": "Очистити", + "ClearLdnPassTooltip": "Очищає поточну пароль, повертаючись до публічної мережі.", + "InvalidLdnPassphrase": "Невірний пароль! Має бути в форматі \"Ryujinx-<8 символів>\"" +} diff --git a/src/Ryujinx/Assets/Locales/zh_CN.json b/src/Ryujinx/Assets/Locales/zh_CN.json index 004d5007b..7c1308a6c 100644 --- a/src/Ryujinx/Assets/Locales/zh_CN.json +++ b/src/Ryujinx/Assets/Locales/zh_CN.json @@ -1,6 +1,7 @@ { "Language": "简体中文", "MenuBarFileOpenApplet": "打开小程序", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "打开独立的 Mii 小程序", "SettingsTabInputDirectMouseAccess": "直通鼠标操作", "SettingsTabSystemMemoryManagerMode": "内存管理模式:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "安装系统固件", "MenuBarFileToolsInstallFirmwareFromFile": "从 XCI 或 ZIP 文件中安装系统固件", "MenuBarFileToolsInstallFirmwareFromDirectory": "从文件夹中安装系统固件", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "管理文件扩展名", "MenuBarToolsInstallFileTypes": "关联文件扩展名", "MenuBarToolsUninstallFileTypes": "取消关联扩展名", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "视图(_V)", "MenuBarViewWindow": "窗口大小", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "帮助(_H)", "MenuBarHelpCheckForUpdates": "检查更新", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "关于", "MenuSearch": "搜索…", "GameListHeaderFavorite": "收藏", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "打开存放游戏 MOD 的目录", "GameListContextMenuOpenSdModsDirectory": "打开大气层系统 MOD 目录", "GameListContextMenuOpenSdModsDirectoryToolTip": "打开存放适用于大气层系统的游戏 MOD 的目录,对于为真实硬件打包的 MOD 非常有用", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} 游戏加载完成", "StatusBarSystemVersion": "系统固件版本:{0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "检测到操作系统内存映射最大数量被设置的过低", "LinuxVmMaxMapCountDialogTextPrimary": "你想要将操作系统 vm.max_map_count 的值增加到 {0} 吗", "LinuxVmMaxMapCountDialogTextSecondary": "有些游戏可能会尝试创建超过当前系统允许的内存映射最大数量,若超过当前最大数量,Ryujinx 模拟器将会闪退。", @@ -400,6 +414,8 @@ "InputDialogTitle": "输入对话框", "InputDialogOk": "完成", "InputDialogCancel": "取消", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "选择用户名称", "InputDialogAddNewProfileHeader": "请输入账户名称", "InputDialogAddNewProfileSubtext": "(最大长度:{0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "正在提取更新...", "DialogUpdaterRenamingMessage": "正在重命名更新...", "DialogUpdaterAddingFilesMessage": "安装更新中...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "更新成功!", "DialogUpdaterRestartMessage": "是否立即重启 Ryujinx 模拟器?", "DialogUpdaterNoInternetMessage": "没有连接到网络", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "成功解除文件类型关联!", "DialogUninstallFileTypesErrorMessage": "解除文件类型关联失败!", "DialogOpenSettingsWindowLabel": "打开设置窗口", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "控制器小窗口", "DialogMessageDialogErrorExceptionMessage": "显示消息对话框时出错:{0}", "DialogSoftwareKeyboardErrorExceptionMessage": "显示软件键盘时出错:{0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n是否继续?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "安装系统固件中...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安装系统固件版本 {0} 。", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "删除后将没有可用的账户", "DialogUserProfileDeletionConfirmMessage": "是否删除所选账户", "DialogUserProfileUnsavedChangesTitle": "警告 - 有未保存的更改", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "在浏览器中打开 Ryujinx 模拟器官网。", "AboutDisclaimerMessage": "Ryujinx 与 Nintendo™ 以及其合作伙伴没有任何关联。", "AboutAmiiboDisclaimerMessage": "我们的 Amiibo 模拟使用了\nAmiiboAPI (www.amiiboapi.com)。", - "AboutPatreonUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Patreon 赞助页。", "AboutGithubUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 GitHub 代码库。", "AboutDiscordUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Discord 邀请链接。", - "AboutTwitterUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Twitter 主页。", "AboutRyujinxAboutTitle": "关于:", - "AboutRyujinxAboutContent": "Ryujinx 是一款 Nintendo Switch™ 模拟器。\n您可以在 Patreon 上赞助 Ryujinx。\n关注 Twitter 或 Discord 可以获取模拟器最新动态。\n如果您对开发感兴趣,欢迎来 GitHub 或 Discord 加入我们!", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "开发维护人员名单:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "在浏览器中打开贡献者页面", - "AboutRyujinxSupprtersTitle": "感谢 Patreon 上的赞助者:", "AmiiboSeriesLabel": "Amiibo 系列", "AmiiboCharacterLabel": "角色", "AmiiboScanButtonLabel": "扫描", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "游戏更新的版本 {0}", "TitleBundledUpdateVersionLabel": "捆绑:版本 {0}", "TitleBundledDlcLabel": "捆绑:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - 信息", "RyujinxConfirm": "Ryujinx - 确认", "FileDialogAllTypes": "全部类型", "Never": "从不", "SwkbdMinCharacters": "不少于 {0} 个字符", "SwkbdMinRangeCharacters": "必须为 {0}-{1} 个字符", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "软键盘", "SoftwareKeyboardModeNumeric": "只能输入 0-9 或 \".\"", "SoftwareKeyboardModeAlphabet": "仅支持非中文字符", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "安装更新中...", "UpdaterExtracting": "正在提取更新...", "UpdaterDownloading": "下载更新中...", - "Game": "游戏", "Docked": "主机模式", "Handheld": "掌机模式", "ConnectionError": "连接错误。", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "选择 DLC 文件", "SelectUpdateDialogTitle": "选择更新文件", "SelectModDialogTitle": "选择 MOD 目录", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "管理用户账户", "CheatWindowTitle": "金手指管理器", "DlcWindowTitle": "管理 {0} ({1}) 的 DLC", "ModWindowTitle": "管理 {0} ({1}) 的 MOD", "UpdateWindowTitle": "游戏更新管理器", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "{0} 个更新被添加", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "{0} 个失效的游戏更新已移除", "ModWindowHeading": "{0} Mod", "UserProfilesEditProfile": "编辑所选", + "Continue": "Continue", "Cancel": "取消", "Save": "保存", "Discard": "放弃", @@ -810,5 +868,17 @@ "MultiplayerMode": "联机模式:", "MultiplayerModeTooltip": "修改 LDN 多人联机游玩模式。\n\nldn_mitm 联机插件将修改游戏中的本地无线和本地游玩功能,使其表现得像局域网一样,允许和其他安装了 ldn_mitm 插件的 Ryujinx 模拟器和破解的任天堂 Switch 主机在同一网络下进行本地连接,实现多人联机游玩。\n\n多人联机游玩要求所有玩家必须运行相同的游戏版本(例如,游戏版本 v13.0.1 无法与 v13.0.0 联机)。\n\n如果不确定,请保持为“禁用”。", "MultiplayerModeDisabled": "禁用", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Locales/zh_TW.json b/src/Ryujinx/Assets/Locales/zh_TW.json index 9bfc243ae..0694fca67 100644 --- a/src/Ryujinx/Assets/Locales/zh_TW.json +++ b/src/Ryujinx/Assets/Locales/zh_TW.json @@ -1,6 +1,7 @@ { "Language": "繁體中文 (台灣)", "MenuBarFileOpenApplet": "開啟小程式", + "MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "在獨立模式下開啟 Mii 編輯器小程式", "SettingsTabInputDirectMouseAccess": "滑鼠直接存取", "SettingsTabSystemMemoryManagerMode": "記憶體管理員模式:", @@ -30,15 +31,25 @@ "MenuBarToolsInstallFirmware": "安裝韌體", "MenuBarFileToolsInstallFirmwareFromFile": "從 XCI 或 ZIP 安裝韌體", "MenuBarFileToolsInstallFirmwareFromDirectory": "從資料夾安裝韌體", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "管理檔案類型", "MenuBarToolsInstallFileTypes": "安裝檔案類型", "MenuBarToolsUninstallFileTypes": "移除檔案類型", + "MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarView": "檢視(_V)", "MenuBarViewWindow": "視窗大小", "MenuBarViewWindow720": "720p", "MenuBarViewWindow1080": "1080p", "MenuBarHelp": "說明(_H)", "MenuBarHelpCheckForUpdates": "檢查更新", + "MenuBarHelpFaq": "FAQ & Troubleshooting Page", + "MenuBarHelpFaqTooltip": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki", + "MenuBarHelpSetup": "Setup & Configuration Guide", + "MenuBarHelpSetupTooltip": "Opens the Setup & Configuration guide on the official Ryujinx wiki", + "MenuBarHelpMultiplayer": "Multiplayer (LDN/LAN) Guide", + "MenuBarHelpMultiplayerTooltip": "Opens the Multiplayer guide on the official Ryujinx wiki", "MenuBarHelpAbout": "關於", "MenuSearch": "搜尋...", "GameListHeaderFavorite": "我的最愛", @@ -84,8 +95,11 @@ "GameListContextMenuOpenModsDirectoryToolTip": "開啟此應用程式模組的資料夾", "GameListContextMenuOpenSdModsDirectory": "開啟 Atmosphere 模組資料夾", "GameListContextMenuOpenSdModsDirectoryToolTip": "開啟此應用程式模組的另一個 SD 卡 Atmosphere 資料夾。適用於為真實硬體封裝的模組。", + "GameListContextMenuTrimXCI": "Check and Trim XCI File", + "GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "StatusBarGamesLoaded": "{0}/{1} 遊戲已載入", "StatusBarSystemVersion": "系統版本: {0}", + "StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "LinuxVmMaxMapCountDialogTitle": "檢測到記憶體映射的低限值", "LinuxVmMaxMapCountDialogTextPrimary": "您是否要將 vm.max_map_count 的數值增至 {0}?", "LinuxVmMaxMapCountDialogTextSecondary": "某些遊戲可能會嘗試建立超過目前允許的記憶體映射。一旦超過此限制,Ryujinx 就會崩潰。", @@ -400,6 +414,8 @@ "InputDialogTitle": "輸入對話方塊", "InputDialogOk": "確定", "InputDialogCancel": "取消", + "InputDialogCancelling": "Cancelling", + "InputDialogClose": "Close", "InputDialogAddNewProfileTitle": "選擇設定檔名稱", "InputDialogAddNewProfileHeader": "請輸入設定檔名稱", "InputDialogAddNewProfileSubtext": "(最大長度: {0})", @@ -451,6 +467,7 @@ "DialogUpdaterExtractionMessage": "正在提取更新...", "DialogUpdaterRenamingMessage": "重新命名更新...", "DialogUpdaterAddingFilesMessage": "加入新更新...", + "DialogUpdaterShowChangelogMessage": "Show Changelog", "DialogUpdaterCompleteMessage": "更新成功!", "DialogUpdaterRestartMessage": "您現在要重新啟動 Ryujinx 嗎?", "DialogUpdaterNoInternetMessage": "您沒有連線到網際網路!", @@ -469,6 +486,7 @@ "DialogUninstallFileTypesSuccessMessage": "成功移除檔案類型!", "DialogUninstallFileTypesErrorMessage": "無法移除檔案類型。", "DialogOpenSettingsWindowLabel": "開啟設定視窗", + "DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogControllerAppletTitle": "控制器小程式", "DialogMessageDialogErrorExceptionMessage": "顯示訊息對話方塊時出現錯誤: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "顯示軟體鍵盤時出現錯誤: {0}", @@ -497,6 +515,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n您確定要繼續嗎?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "正在安裝韌體...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安裝系統版本 {0}。", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "如果刪除選取的設定檔,將無法開啟其他設定檔", "DialogUserProfileDeletionConfirmMessage": "您是否要刪除所選設定檔", "DialogUserProfileUnsavedChangesTitle": "警告 - 未儲存的變更", @@ -533,15 +558,13 @@ "AboutUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 網站。", "AboutDisclaimerMessage": "Ryujinx 和 Nintendo™\n或其任何合作夥伴完全沒有關聯。", "AboutAmiiboDisclaimerMessage": "我們在 Amiibo 模擬中\n使用了 AmiiboAPI (www.amiiboapi.com)。", - "AboutPatreonUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Patreon 網頁。", "AboutGithubUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 GitHub 網頁。", "AboutDiscordUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Discord 邀請連結。", - "AboutTwitterUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Twitter 網頁。", "AboutRyujinxAboutTitle": "關於:", - "AboutRyujinxAboutContent": "Ryujinx 是一款 Nintendo Switch™ 模擬器。\n請在 Patreon 上支持我們。\n關注我們的 Twitter 或 Discord 取得所有最新消息。\n對於有興趣貢獻的開發者,可以在我們的 GitHub 或 Discord 上了解更多資訊。", + "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxMaintainersTitle": "維護者:", + "AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:", "AboutRyujinxMaintainersContentTooltipMessage": "在預設瀏覽器中開啟貢獻者的網頁", - "AboutRyujinxSupprtersTitle": "Patreon 支持者:", "AmiiboSeriesLabel": "Amiibo 系列", "AmiiboCharacterLabel": "角色", "AmiiboScanButtonLabel": "掃描", @@ -671,12 +694,21 @@ "TitleUpdateVersionLabel": "版本 {0}", "TitleBundledUpdateVersionLabel": "附帶: 版本 {0}", "TitleBundledDlcLabel": "附帶:", + "TitleXCIStatusPartialLabel": "Partial", + "TitleXCIStatusTrimmableLabel": "Untrimmed", + "TitleXCIStatusUntrimmableLabel": "Trimmed", + "TitleXCIStatusFailedLabel": "(Failed)", + "TitleXCICanSaveLabel": "Save {0:n0} Mb", + "TitleXCISavingLabel": "Saved {0:n0} Mb", "RyujinxInfo": "Ryujinx - 資訊", "RyujinxConfirm": "Ryujinx - 確認", "FileDialogAllTypes": "全部類型", "Never": "從不", "SwkbdMinCharacters": "長度必須至少為 {0} 個字元", "SwkbdMinRangeCharacters": "長度必須為 {0} 到 {1} 個字元", + "CabinetTitle": "Cabinet Dialog", + "CabinetDialog": "Enter your Amiibo's new name", + "CabinetScanDialog": "Please scan your Amiibo now.", "SoftwareKeyboard": "軟體鍵盤", "SoftwareKeyboardModeNumeric": "必須是 0 到 9 或「.」", "SoftwareKeyboardModeAlphabet": "必須是「非中日韓字元」 (non CJK)", @@ -690,7 +722,6 @@ "UpdaterAddingFiles": "正在加入新檔案...", "UpdaterExtracting": "正在提取更新...", "UpdaterDownloading": "正在下載更新...", - "Game": "遊戲", "Docked": "底座模式", "Handheld": "手提模式", "ConnectionError": "連線錯誤。", @@ -723,11 +754,37 @@ "SelectDlcDialogTitle": "選取 DLC 檔案", "SelectUpdateDialogTitle": "選取更新檔", "SelectModDialogTitle": "選取模組資料夾", + "TrimXCIFileDialogTitle": "Check and Trim XCI File", + "TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", + "TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", + "TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", + "TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", + "TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", + "TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", + "TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", + "TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", + "TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", + "TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", + "TrimXCIFileCancelled": "The operation was cancelled", + "TrimXCIFileFileUndertermined": "No operation was performed", "UserProfileWindowTitle": "使用者設定檔管理員", "CheatWindowTitle": "密技管理員", "DlcWindowTitle": "管理 {0} 的可下載內容 ({1})", "ModWindowTitle": "管理 {0} 的模組 ({1})", "UpdateWindowTitle": "遊戲更新管理員", + "XCITrimmerWindowTitle": "XCI File Trimmer", + "XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", + "XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", + "XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", + "XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", + "XCITrimmerTitleStatusFailed": "Failed", + "XCITrimmerPotentialSavings": "Potential Savings", + "XCITrimmerActualSavings": "Actual Savings", + "XCITrimmerSavingsMb": "{0:n0} Mb", + "XCITrimmerSelectDisplayed": "Select Shown", + "XCITrimmerDeselectDisplayed": "Deselect Shown", + "XCITrimmerSortName": "Title", + "XCITrimmerSortSaved": "Space Savings", "XCITrimmerTrim": "Trim", "XCITrimmerUntrim": "Untrim", "UpdateWindowUpdateAddedMessage": "已加入 {0} 個遊戲更新", @@ -735,7 +792,7 @@ "CheatWindowHeading": "可用於 {0} [{1}] 的密技", "BuildId": "組建識別碼:", "DlcWindowBundledContentNotice": "附帶的 DLC 只能被停用而無法被刪除。", - "DlcWindowHeading": "{0} 個可下載內容", + "DlcWindowHeading": "{0} DLC(s) available", "DlcWindowDlcAddedMessage": "已加入 {0} 個 DLC", "AutoloadDlcAddedMessage": "已加入 {0} 個 DLC", "AutoloadDlcRemovedMessage": "已刪除 {0} 個遺失的 DLC", @@ -743,6 +800,7 @@ "AutoloadUpdateRemovedMessage": "已刪除 {0} 個遺失的遊戲更新", "ModWindowHeading": "{0} 模組", "UserProfilesEditProfile": "編輯所選", + "Continue": "Continue", "Cancel": "取消", "Save": "儲存", "Discard": "放棄變更", @@ -810,5 +868,17 @@ "MultiplayerMode": "模式:", "MultiplayerModeTooltip": "變更 LDN 多人遊戲模式。\n\nLdnMitm 將修改遊戲中的本機無線/本機遊戲功能,使其如同區域網路一樣執行,允許與其他安裝了 ldn_mitm 模組的 Ryujinx 實例和已破解的 Nintendo Switch 遊戲機進行本機同網路連線。\n\n多人遊戲要求所有玩家使用相同的遊戲版本 (例如,Super Smash Bros. Ultimate v13.0.1 無法連接 v13.0.0)。\n\n如果不確定,請保持 Disabled (停用) 狀態。", "MultiplayerModeDisabled": "已停用", - "MultiplayerModeLdnMitm": "ldn_mitm" + "MultiplayerModeLdnMitm": "ldn_mitm", + "MultiplayerModeLdnRyu": "RyuLDN", + "MultiplayerDisableP2P": "Disable P2P Network Hosting (may increase latency)", + "MultiplayerDisableP2PTooltip": "Disable P2P network hosting, peers will proxy through the master server instead of connecting to you directly.", + "LdnPassphrase": "Network Passphrase:", + "LdnPassphraseTooltip": "You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputTooltip": "Enter a passphrase in the format Ryujinx-<8 hex chars>. You will only be able to see hosted games with the same passphrase as you.", + "LdnPassphraseInputPublic": "(public)", + "GenLdnPass": "Generate Random", + "GenLdnPassTooltip": "Generates a new passphrase, which can be shared with other players.", + "ClearLdnPass": "Clear", + "ClearLdnPassTooltip": "Clears the current passphrase, returning to the public network.", + "InvalidLdnPassphrase": "Invalid Passphrase! Must be in the format \"Ryujinx-<8 hex chars>\"" } diff --git a/src/Ryujinx/Assets/Styles/Styles.xaml b/src/Ryujinx/Assets/Styles/Styles.xaml index 05212a7dd..878b5e7f1 100644 --- a/src/Ryujinx/Assets/Styles/Styles.xaml +++ b/src/Ryujinx/Assets/Styles/Styles.xaml @@ -1,7 +1,8 @@  + xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" + xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia"> @@ -231,7 +232,7 @@ - diff --git a/src/Ryujinx/Assets/Styles/Themes.xaml b/src/Ryujinx/Assets/Styles/Themes.xaml index 0f323f84b..46e298035 100644 --- a/src/Ryujinx/Assets/Styles/Themes.xaml +++ b/src/Ryujinx/Assets/Styles/Themes.xaml @@ -4,18 +4,6 @@ - - - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FFe8e8e8 #FF00FABB #FFF0F0F0 #FFd6d6d6 @@ -26,24 +14,14 @@ #b3ffffff #80cccccc #A0000000 - #FF2EEAC9 - #FFFF4554 + #fffcd12a + #FF2EEAC9 + #FFFF4554 + #6483F5 - - - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FF00C3E3 - #FFe8e8e8 #FF00FABB #FFF0F0F0 #FFd6d6d6 @@ -58,18 +36,7 @@ - - #008AA8 - #FF00C3E3 - #FF99b000 - #FF006d7d - #FF00525E - #FF00dbff - #FF19dfff - #FF33e3ff #FF00FABB #FF2D2D2D #FF505050 diff --git a/src/Ryujinx/Common/KeyboardHotkeyState.cs b/src/Ryujinx/Common/KeyboardHotkeyState.cs index 6e4920988..060c678d2 100644 --- a/src/Ryujinx/Common/KeyboardHotkeyState.cs +++ b/src/Ryujinx/Common/KeyboardHotkeyState.cs @@ -3,7 +3,7 @@ namespace Ryujinx.Ava.Common public enum KeyboardHotkeyState { None, - ToggleVSync, + ToggleVSyncMode, Screenshot, ShowUI, Pause, @@ -12,5 +12,7 @@ namespace Ryujinx.Ava.Common ResScaleDown, VolumeUp, VolumeDown, + CustomVSyncIntervalIncrement, + CustomVSyncIntervalDecrement, } } diff --git a/src/Ryujinx/Common/Markup/BasicMarkupExtension.cs b/src/Ryujinx/Common/Markup/BasicMarkupExtension.cs index 67c016562..b1b7361a6 100644 --- a/src/Ryujinx/Common/Markup/BasicMarkupExtension.cs +++ b/src/Ryujinx/Common/Markup/BasicMarkupExtension.cs @@ -17,13 +17,13 @@ namespace Ryujinx.Ava.Common.Markup public virtual string Name => "Item"; public virtual Action? Setter => null; - protected abstract T? GetValue(); + protected abstract T? Value { get; } protected virtual void ConfigureBindingExtension(CompiledBindingExtension _) { } private ClrPropertyInfo PropertyInfo => new(Name, - _ => GetValue(), + _ => Value, Setter as Action, typeof(T)); diff --git a/src/Ryujinx/Common/Markup/MarkupExtensions.cs b/src/Ryujinx/Common/Markup/MarkupExtensions.cs index a804792c7..cae6d8c2c 100644 --- a/src/Ryujinx/Common/Markup/MarkupExtensions.cs +++ b/src/Ryujinx/Common/Markup/MarkupExtensions.cs @@ -6,17 +6,17 @@ namespace Ryujinx.Ava.Common.Markup { internal class IconExtension(string iconString) : BasicMarkupExtension { - protected override Icon GetValue() => new() { Value = iconString }; + protected override Icon Value => new() { Value = iconString }; } internal class SpinningIconExtension(string iconString) : BasicMarkupExtension { - protected override Icon GetValue() => new() { Value = iconString, Animation = IconAnimation.Spin }; + protected override Icon Value => new() { Value = iconString, Animation = IconAnimation.Spin }; } internal class LocaleExtension(LocaleKeys key) : BasicMarkupExtension { - protected override string GetValue() => LocaleManager.Instance[key]; + protected override string Value => LocaleManager.Instance[key]; protected override void ConfigureBindingExtension(CompiledBindingExtension bindingExtension) => bindingExtension.Source = LocaleManager.Instance; diff --git a/src/Ryujinx/Common/XCIFileTrimmerMainWindowLog.cs b/src/Ryujinx/Common/XCIFileTrimmerMainWindowLog.cs deleted file mode 100644 index 98347968e..000000000 --- a/src/Ryujinx/Common/XCIFileTrimmerMainWindowLog.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Avalonia.Threading; -using Ryujinx.Ava.UI.ViewModels; - -namespace Ryujinx.Ava.Common -{ - internal class XCIFileTrimmerMainWindowLog : Ryujinx.Common.Logging.XCIFileTrimmerLog - { - private readonly MainWindowViewModel _viewModel; - - public XCIFileTrimmerMainWindowLog(MainWindowViewModel viewModel) - { - _viewModel = viewModel; - } - - public override void Progress(long current, long total, string text, bool complete) - { - Dispatcher.UIThread.Post(() => - { - _viewModel.StatusBarProgressMaximum = (int)(total); - _viewModel.StatusBarProgressValue = (int)(current); - }); - } - } -} diff --git a/src/Ryujinx/Common/XCIFileTrimmerWindowLog.cs b/src/Ryujinx/Common/XCIFileTrimmerWindowLog.cs deleted file mode 100644 index 2481d9107..000000000 --- a/src/Ryujinx/Common/XCIFileTrimmerWindowLog.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Avalonia.Threading; -using Ryujinx.Ava.UI.ViewModels; - -namespace Ryujinx.Ava.Common -{ - internal class XCIFileTrimmerWindowLog : Ryujinx.Common.Logging.XCIFileTrimmerLog - { - private readonly XCITrimmerViewModel _viewModel; - - public XCIFileTrimmerWindowLog(XCITrimmerViewModel viewModel) - { - _viewModel = viewModel; - } - - public override void Progress(long current, long total, string text, bool complete) - { - Dispatcher.UIThread.Post(() => - { - _viewModel.SetProgress((int)(current), (int)(total)); - }); - } - } -} diff --git a/src/Ryujinx/Common/XCITrimmerLog.cs b/src/Ryujinx/Common/XCITrimmerLog.cs new file mode 100644 index 000000000..b661d918d --- /dev/null +++ b/src/Ryujinx/Common/XCITrimmerLog.cs @@ -0,0 +1,45 @@ +using Avalonia.Threading; +using Ryujinx.Ava.UI.ViewModels; + +namespace Ryujinx.Ava.Common +{ + public static class XCITrimmerLog + { + internal class MainWindow : Ryujinx.Common.Logging.XCIFileTrimmerLog + { + private readonly MainWindowViewModel _viewModel; + + public MainWindow(MainWindowViewModel viewModel) + { + _viewModel = viewModel; + } + + public override void Progress(long current, long total, string text, bool complete) + { + Dispatcher.UIThread.Post(() => + { + _viewModel.StatusBarProgressMaximum = (int)(total); + _viewModel.StatusBarProgressValue = (int)(current); + }); + } + } + + internal class TrimmerWindow : Ryujinx.Common.Logging.XCIFileTrimmerLog + { + private readonly XCITrimmerViewModel _viewModel; + + public TrimmerWindow(XCITrimmerViewModel viewModel) + { + _viewModel = viewModel; + } + + public override void Progress(long current, long total, string text, bool complete) + { + Dispatcher.UIThread.Post(() => + { + _viewModel.SetProgress((int)(current), (int)(total)); + }); + } + } + } +} diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj index b41ec1cd4..989a3a5bd 100644 --- a/src/Ryujinx/Ryujinx.csproj +++ b/src/Ryujinx/Ryujinx.csproj @@ -11,6 +11,7 @@ true true app.manifest + $(DefaultItemExcludes);._* diff --git a/src/Ryujinx/Ryujinx.ico b/src/Ryujinx/Ryujinx.ico index 0da5a311f..e1ac423e7 100644 Binary files a/src/Ryujinx/Ryujinx.ico and b/src/Ryujinx/Ryujinx.ico differ diff --git a/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs b/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs index 2ebba7ac0..893ea95ac 100644 --- a/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs +++ b/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs @@ -7,6 +7,7 @@ using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Windows; using Ryujinx.HLE; using Ryujinx.HLE.HOS.Applets; +using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; using Ryujinx.HLE.UI; using Ryujinx.UI.Common.Configuration; @@ -155,6 +156,55 @@ namespace Ryujinx.Ava.UI.Applet return error || okPressed; } + public bool DisplayCabinetDialog(out string userText) + { + ManualResetEvent dialogCloseEvent = new(false); + bool okPressed = false; + string inputText = "My Amiibo"; + Dispatcher.UIThread.InvokeAsync(async () => + { + try + { + _parent.ViewModel.AppHost.NpadManager.BlockInputUpdates(); + SoftwareKeyboardUIArgs args = new SoftwareKeyboardUIArgs(); + args.KeyboardMode = KeyboardMode.Default; + args.InitialText = "Ryujinx"; + args.StringLengthMin = 1; + args.StringLengthMax = 25; + (UserResult result, string userInput) = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.CabinetDialog], args); + if (result == UserResult.Ok) + { + inputText = userInput; + okPressed = true; + } + } + finally + { + dialogCloseEvent.Set(); + } + }); + dialogCloseEvent.WaitOne(); + _parent.ViewModel.AppHost.NpadManager.UnblockInputUpdates(); + userText = inputText; + return okPressed; + } + + public void DisplayCabinetMessageDialog() + { + ManualResetEvent dialogCloseEvent = new(false); + Dispatcher.UIThread.InvokeAsync(async () => + { + dialogCloseEvent.Set(); + await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.CabinetScanDialog], + string.Empty, + LocaleManager.Instance[LocaleKeys.InputDialogOk], + string.Empty, + LocaleManager.Instance[LocaleKeys.CabinetTitle]); + }); + dialogCloseEvent.WaitOne(); + } + + public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value) { device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value); diff --git a/src/Ryujinx/UI/Controls/ApplicationGridView.axaml b/src/Ryujinx/UI/Controls/ApplicationGridView.axaml index 98a1c004b..3bcb468ae 100644 --- a/src/Ryujinx/UI/Controls/ApplicationGridView.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationGridView.axaml @@ -91,7 +91,7 @@ HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="16" - Foreground="{DynamicResource SystemAccentColor}" + Foreground="{DynamicResource FavoriteApplicationIconColor}" IsVisible="{Binding Favorite}" Symbol="StarFilled" /> diff --git a/src/Ryujinx/UI/Controls/ApplicationListView.axaml b/src/Ryujinx/UI/Controls/ApplicationListView.axaml index 0daa77ac4..8a72ebfbf 100644 --- a/src/Ryujinx/UI/Controls/ApplicationListView.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationListView.axaml @@ -146,7 +146,7 @@ HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="16" - Foreground="{DynamicResource SystemAccentColor}" + Foreground="{DynamicResource FavoriteApplicationIconColor}" IsVisible="{Binding Favorite}" Symbol="StarFilled" /> diff --git a/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs b/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs index a7fe3f0ce..3f0f0f033 100644 --- a/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs +++ b/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs @@ -261,6 +261,16 @@ namespace Ryujinx.Ava.UI.Helpers string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], (int)Symbol.Important); + + internal static async Task CreateUpdaterUpToDateInfoDialog(string primary, string secondaryText) + => await ShowTextDialog( + LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle], + primary, + secondaryText, + LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage], + string.Empty, + LocaleManager.Instance[LocaleKeys.InputDialogOk], + (int)Symbol.Important); internal static async Task CreateWarningDialog(string primary, string secondaryText) => await ShowTextDialog( @@ -309,6 +319,30 @@ namespace Ryujinx.Ava.UI.Helpers return response == UserResult.Yes; } + + internal static async Task CreateUpdaterChoiceDialog(string title, string primary, string secondaryText) + { + if (_isChoiceDialogOpen) + { + return UserResult.Cancel; + } + + _isChoiceDialogOpen = true; + + UserResult response = await ShowTextDialog( + title, + primary, + secondaryText, + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + (int)Symbol.Help, + UserResult.Yes); + + _isChoiceDialogOpen = false; + + return response; + } internal static async Task CreateExitDialog() { diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs index b5f53508b..4c7a6bd02 100644 --- a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs +++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs @@ -5,13 +5,13 @@ namespace Ryujinx.Ava.UI.Models.Input { public class HotkeyConfig : BaseModel { - private Key _toggleVsync; - public Key ToggleVsync + private Key _toggleVSyncMode; + public Key ToggleVSyncMode { - get => _toggleVsync; + get => _toggleVSyncMode; set { - _toggleVsync = value; + _toggleVSyncMode = value; OnPropertyChanged(); } } @@ -104,11 +104,33 @@ namespace Ryujinx.Ava.UI.Models.Input } } + private Key _customVSyncIntervalIncrement; + public Key CustomVSyncIntervalIncrement + { + get => _customVSyncIntervalIncrement; + set + { + _customVSyncIntervalIncrement = value; + OnPropertyChanged(); + } + } + + private Key _customVSyncIntervalDecrement; + public Key CustomVSyncIntervalDecrement + { + get => _customVSyncIntervalDecrement; + set + { + _customVSyncIntervalDecrement = value; + OnPropertyChanged(); + } + } + public HotkeyConfig(KeyboardHotkeys config) { if (config != null) { - ToggleVsync = config.ToggleVsync; + ToggleVSyncMode = config.ToggleVSyncMode; Screenshot = config.Screenshot; ShowUI = config.ShowUI; Pause = config.Pause; @@ -117,6 +139,8 @@ namespace Ryujinx.Ava.UI.Models.Input ResScaleDown = config.ResScaleDown; VolumeUp = config.VolumeUp; VolumeDown = config.VolumeDown; + CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement; + CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement; } } @@ -124,7 +148,7 @@ namespace Ryujinx.Ava.UI.Models.Input { var config = new KeyboardHotkeys { - ToggleVsync = ToggleVsync, + ToggleVSyncMode = ToggleVSyncMode, Screenshot = Screenshot, ShowUI = ShowUI, Pause = Pause, @@ -133,6 +157,8 @@ namespace Ryujinx.Ava.UI.Models.Input ResScaleDown = ResScaleDown, VolumeUp = VolumeUp, VolumeDown = VolumeDown, + CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement, + CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement, }; return config; diff --git a/src/Ryujinx/UI/Models/SaveModel.cs b/src/Ryujinx/UI/Models/SaveModel.cs index 55408ac3a..cfc397c6e 100644 --- a/src/Ryujinx/UI/Models/SaveModel.cs +++ b/src/Ryujinx/UI/Models/SaveModel.cs @@ -47,7 +47,7 @@ namespace Ryujinx.Ava.UI.Models TitleId = info.ProgramId; UserId = info.UserId; - var appData = App.MainWindow.ViewModel.Applications.FirstOrDefault(x => x.IdString.Equals(TitleIdString, StringComparison.OrdinalIgnoreCase)); + var appData = MainWindow.MainWindowViewModel.Applications.FirstOrDefault(x => x.IdString.Equals(TitleIdString, StringComparison.OrdinalIgnoreCase)); InGameList = appData != null; diff --git a/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs b/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs index 40f783c44..6f0f5ab5d 100644 --- a/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs +++ b/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs @@ -4,18 +4,17 @@ namespace Ryujinx.Ava.UI.Models { internal class StatusUpdatedEventArgs : EventArgs { - public bool VSyncEnabled { get; } + public string VSyncMode { get; } public string VolumeStatus { get; } public string AspectRatio { get; } public string DockedMode { get; } public string FifoStatus { get; } public string GameStatus { get; } - public uint ShaderCount { get; } - public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, uint shaderCount) + public StatusUpdatedEventArgs(string vSyncMode, string volumeStatus, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, uint shaderCount) { - VSyncEnabled = vSyncEnabled; + VSyncMode = vSyncMode; VolumeStatus = volumeStatus; DockedMode = dockedMode; AspectRatio = aspectRatio; diff --git a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs index 236711c31..23d0f963c 100644 --- a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs @@ -45,11 +45,13 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public string Developers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz, GreemDev"); + public string Developers => "GreemDev"; + + public string FormerDevelopers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz"); public AboutWindowViewModel() { - Version = Program.Version; + Version = App.FullAppName + "\n" + Program.Version; UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value); ThemeManager.ThemeChanged += ThemeManager_ThemeChanged; diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index f1587a0ff..39a7fd2a9 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -10,6 +10,7 @@ using DynamicData; using DynamicData.Binding; using FluentAvalonia.UI.Controls; using LibHac.Common; +using LibHac.Ns; using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Input; @@ -63,13 +64,14 @@ namespace Ryujinx.Ava.UI.ViewModels private string _searchText; private Timer _searchTimer; private string _dockedStatusText; + private string _vSyncModeText; private string _fifoStatusText; private string _gameStatusText; private string _volumeStatusText; private string _gpuStatusText; private string _shaderCountText; private bool _isAmiiboRequested; - private bool _showRightmostSeparator; + private bool _showShaderCompilationHint; private bool _isGameRunning; private bool _isFullScreen; private int _progressMaximum; @@ -80,7 +82,7 @@ namespace Ryujinx.Ava.UI.ViewModels private bool _showStatusSeparator; private Brush _progressBarForegroundColor; private Brush _progressBarBackgroundColor; - private Brush _vsyncColor; + private Brush _vSyncModeColor; private byte[] _selectedIcon; private bool _isAppletMenuActive; private int _statusBarProgressMaximum; @@ -111,6 +113,8 @@ namespace Ryujinx.Ava.UI.ViewModels private WindowState _windowState; private double _windowWidth; private double _windowHeight; + private int _customVSyncInterval; + private int _customVSyncIntervalPercentageProxy; private bool _isActive; private bool _isSubMenuOpen; @@ -121,7 +125,7 @@ namespace Ryujinx.Ava.UI.ViewModels public IEnumerable LastLdnGameData; public static readonly Bitmap IconBitmap = - new(Assembly.GetAssembly(typeof(ConfigurationState))!.GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Ryujinx.png")!); + new(Assembly.GetAssembly(typeof(ConfigurationState))!.GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Thiccjinx.png")!); public MainWindow Window { get; init; } @@ -145,6 +149,7 @@ namespace Ryujinx.Ava.UI.ViewModels Volume = ConfigurationState.Instance.System.AudioVolume; } + CustomVSyncInterval = ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value; } public void Initialize( @@ -271,12 +276,12 @@ namespace Ryujinx.Ava.UI.ViewModels public bool ShowFirmwareStatus => !ShowLoadProgress; - public bool ShowRightmostSeparator + public bool ShowShaderCompilationHint { - get => _showRightmostSeparator; + get => _showShaderCompilationHint; set { - _showRightmostSeparator = value; + _showShaderCompilationHint = value; OnPropertyChanged(); } @@ -397,7 +402,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool OpenDeviceSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0; - public bool TrimXCIEnabled => Ryujinx.Common.Utilities.XCIFileTrimmer.CanTrim(SelectedApplication.Path, new Common.XCIFileTrimmerMainWindowLog(this)); + public bool TrimXCIEnabled => XCIFileTrimmer.CanTrim(SelectedApplication.Path, new XCITrimmerLog.MainWindow(this)); public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; @@ -447,17 +452,87 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public Brush VsyncColor + public Brush VSyncModeColor { - get => _vsyncColor; + get => _vSyncModeColor; set { - _vsyncColor = value; + _vSyncModeColor = value; OnPropertyChanged(); } } + public bool ShowCustomVSyncIntervalPicker + { + get + { + if (_isGameRunning) + { + return AppHost.Device.VSyncMode == + VSyncMode.Custom; + } + else + { + return false; + } + } + set + { + OnPropertyChanged(); + } + } + + public int CustomVSyncIntervalPercentageProxy + { + get => _customVSyncIntervalPercentageProxy; + set + { + int newInterval = (int)((value / 100f) * 60); + _customVSyncInterval = newInterval; + _customVSyncIntervalPercentageProxy = value; + if (_isGameRunning) + { + AppHost.Device.CustomVSyncInterval = newInterval; + AppHost.Device.UpdateVSyncInterval(); + } + OnPropertyChanged((nameof(CustomVSyncInterval))); + OnPropertyChanged((nameof(CustomVSyncIntervalPercentageText))); + } + } + + public string CustomVSyncIntervalPercentageText + { + get + { + string text = CustomVSyncIntervalPercentageProxy.ToString() + "%"; + return text; + } + set + { + + } + } + + public int CustomVSyncInterval + { + get => _customVSyncInterval; + set + { + _customVSyncInterval = value; + int newPercent = (int)((value / 60f) * 100); + _customVSyncIntervalPercentageProxy = newPercent; + if (_isGameRunning) + { + AppHost.Device.CustomVSyncInterval = value; + AppHost.Device.UpdateVSyncInterval(); + } + OnPropertyChanged(nameof(CustomVSyncIntervalPercentageProxy)); + OnPropertyChanged(nameof(CustomVSyncIntervalPercentageText)); + OnPropertyChanged(); + } + } + public byte[] SelectedIcon { get => _selectedIcon; @@ -578,6 +653,17 @@ namespace Ryujinx.Ava.UI.ViewModels } } + public string VSyncModeText + { + get => _vSyncModeText; + set + { + _vSyncModeText = value; + + OnPropertyChanged(); + } + } + public string DockedStatusText { get => _dockedStatusText; @@ -1186,6 +1272,108 @@ namespace Ryujinx.Ava.UI.ViewModels } } + private async Task HandleKeysInstallation(string filename) + { + try + { + string systemDirectory = AppDataManager.KeysDirPath; + if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && Directory.Exists(AppDataManager.KeysDirPathUser)) + { + systemDirectory = AppDataManager.KeysDirPathUser; + } + + string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallTitle); + string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallMessage); + + bool alreadyKesyInstalled = ContentManager.AreKeysAlredyPresent(systemDirectory); + if (alreadyKesyInstalled) + { + dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallSubMessage); + } + + dialogMessage += LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallConfirmMessage]; + + UserResult result = await ContentDialogHelper.CreateConfirmationDialog( + dialogTitle, + dialogMessage, + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + + UpdateWaitWindow waitingDialog = new(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallWaitMessage]); + + if (result == UserResult.Yes) + { + Logger.Info?.Print(LogClass.Application, $"Installing Keys"); + + Thread thread = new(() => + { + Dispatcher.UIThread.InvokeAsync(delegate + { + waitingDialog.Show(); + }); + + try + { + ContentManager.InstallKeys(filename, systemDirectory); + + Dispatcher.UIThread.InvokeAsync(async delegate + { + waitingDialog.Close(); + + string message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallSuccessMessage); + + await ContentDialogHelper.CreateInfoDialog( + dialogTitle, + message, + LocaleManager.Instance[LocaleKeys.InputDialogOk], + string.Empty, + LocaleManager.Instance[LocaleKeys.RyujinxInfo]); + + Logger.Info?.Print(LogClass.Application, message); + }); + } + catch (Exception ex) + { + Dispatcher.UIThread.InvokeAsync(async () => + { + waitingDialog.Close(); + + string message = ex.Message; + if(ex is FormatException) + { + message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysNotFoundErrorMessage, filename); + } + + await ContentDialogHelper.CreateErrorDialog(message); + }); + } + finally + { + VirtualFileSystem.ReloadKeySet(); + } + }) + { + Name = "GUI.KeysInstallerThread", + }; + + thread.Start(); + } + } + catch (MissingKeyException ex) + { + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime) + { + Logger.Error?.Print(LogClass.Application, ex.ToString()); + + await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys); + } + } + catch (Exception ex) + { + await ContentDialogHelper.CreateErrorDialog(ex.Message); + } + } private void ProgressHandler(T state, int current, int total) where T : Enum { Dispatcher.UIThread.Post(() => @@ -1292,24 +1480,25 @@ namespace Ryujinx.Ava.UI.ViewModels { Dispatcher.UIThread.InvokeAsync(() => { - Application.Current!.Styles.TryGetResource(args.VSyncEnabled - ? "VsyncEnabled" - : "VsyncDisabled", + Application.Current!.Styles.TryGetResource(args.VSyncMode, Application.Current.ActualThemeVariant, out object color); if (color is Color clr) { - VsyncColor = new SolidColorBrush(clr); + VSyncModeColor = new SolidColorBrush(clr); } + VSyncModeText = args.VSyncMode == "Custom" ? "Custom" : "VSync"; + ShowCustomVSyncIntervalPicker = + args.VSyncMode == VSyncMode.Custom.ToString(); DockedStatusText = args.DockedMode; AspectRatioStatusText = args.AspectRatio; GameStatusText = args.GameStatus; VolumeStatusText = args.VolumeStatus; FifoStatusText = args.FifoStatus; - ShaderCountText = (ShowRightmostSeparator = args.ShaderCount > 0) + ShaderCountText = (ShowShaderCompilationHint = args.ShaderCount > 0) ? $"{LocaleManager.Instance[LocaleKeys.CompilingShaders]}: {args.ShaderCount}" : string.Empty; @@ -1473,6 +1662,53 @@ namespace Ryujinx.Ava.UI.ViewModels } } + public async Task InstallKeysFromFile() + { + var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + AllowMultiple = false, + FileTypeFilter = new List + { + new(LocaleManager.Instance[LocaleKeys.FileDialogAllTypes]) + { + Patterns = new[] { "*.keys", "*.zip" }, + AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci", "public.zip-archive" }, + MimeTypes = new[] { "application/keys", "application/zip" }, + }, + new("KEYS") + { + Patterns = new[] { "*.keys" }, + AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci" }, + MimeTypes = new[] { "application/keys" }, + }, + new("ZIP") + { + Patterns = new[] { "*.zip" }, + AppleUniformTypeIdentifiers = new[] { "public.zip-archive" }, + MimeTypes = new[] { "application/zip" }, + }, + }, + }); + + if (result.Count > 0) + { + await HandleKeysInstallation(result[0].Path.LocalPath); + } + } + + public async Task InstallKeysFromFolder() + { + var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions + { + AllowMultiple = false, + }); + + if (result.Count > 0) + { + await HandleKeysInstallation(result[0].Path.LocalPath); + } + } + public void OpenRyujinxFolder() { OpenHelper.OpenFolder(AppDataManager.BaseDirPath); @@ -1495,6 +1731,27 @@ namespace Ryujinx.Ava.UI.ViewModels } } + public void ToggleVSyncMode() + { + AppHost.VSyncModeToggle(); + OnPropertyChanged(nameof(ShowCustomVSyncIntervalPicker)); + } + + public void VSyncModeSettingChanged() + { + if (_isGameRunning) + { + AppHost.Device.CustomVSyncInterval = ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value; + AppHost.Device.UpdateVSyncInterval(); + } + + CustomVSyncInterval = ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value; + OnPropertyChanged(nameof(ShowCustomVSyncIntervalPicker)); + OnPropertyChanged(nameof(CustomVSyncIntervalPercentageProxy)); + OnPropertyChanged(nameof(CustomVSyncIntervalPercentageText)); + OnPropertyChanged(nameof(CustomVSyncInterval)); + } + public async Task ExitCurrentState() { if (WindowState is WindowState.FullScreen) @@ -1641,7 +1898,7 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public async Task LoadApplication(ApplicationData application, bool startFullscreen = false) + public async Task LoadApplication(ApplicationData application, bool startFullscreen = false, BlitStruct? customNacpData = null) { if (AppHost != null) { @@ -1679,7 +1936,7 @@ namespace Ryujinx.Ava.UI.ViewModels this, TopLevel); - if (!await AppHost.LoadGuestApplication()) + if (!await AppHost.LoadGuestApplication(customNacpData)) { AppHost.DisposeContext(); AppHost = null; @@ -1908,7 +2165,7 @@ namespace Ryujinx.Ava.UI.ViewModels return; } - var trimmer = new XCIFileTrimmer(filename, new Common.XCIFileTrimmerMainWindowLog(this)); + var trimmer = new XCIFileTrimmer(filename, new XCITrimmerLog.MainWindow(this)); if (trimmer.CanBeTrimmed) { diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index 2da252d00..a5abeb36b 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -52,6 +52,10 @@ namespace Ryujinx.Ava.UI.ViewModels private int _graphicsBackendIndex; private int _scalingFilter; private int _scalingFilterLevel; + private int _customVSyncInterval; + private bool _enableCustomVSyncInterval; + private int _customVSyncIntervalPercentageProxy; + private VSyncMode _vSyncMode; public event Action CloseWindow; public event Action SaveSettingsEvent; @@ -154,7 +158,74 @@ namespace Ryujinx.Ava.UI.ViewModels public bool EnableDockedMode { get; set; } public bool EnableKeyboard { get; set; } public bool EnableMouse { get; set; } - public bool EnableVsync { get; set; } + public VSyncMode VSyncMode + { + get => _vSyncMode; + set + { + if (value == VSyncMode.Custom || + value == VSyncMode.Switch || + value == VSyncMode.Unbounded) + { + _vSyncMode = value; + OnPropertyChanged(); + } + } + } + + public int CustomVSyncIntervalPercentageProxy + { + get => _customVSyncIntervalPercentageProxy; + set + { + int newInterval = (int)((value / 100f) * 60); + _customVSyncInterval = newInterval; + _customVSyncIntervalPercentageProxy = value; + OnPropertyChanged((nameof(CustomVSyncInterval))); + OnPropertyChanged((nameof(CustomVSyncIntervalPercentageText))); + } + } + + public string CustomVSyncIntervalPercentageText + { + get + { + string text = CustomVSyncIntervalPercentageProxy.ToString() + "%"; + return text; + } + } + + public bool EnableCustomVSyncInterval + { + get => _enableCustomVSyncInterval; + set + { + _enableCustomVSyncInterval = value; + if (_vSyncMode == VSyncMode.Custom && !value) + { + VSyncMode = VSyncMode.Switch; + } + else if (value) + { + VSyncMode = VSyncMode.Custom; + } + OnPropertyChanged(); + } + } + + public int CustomVSyncInterval + { + get => _customVSyncInterval; + set + { + _customVSyncInterval = value; + int newPercent = (int)((value / 60f) * 100); + _customVSyncIntervalPercentageProxy = newPercent; + OnPropertyChanged(nameof(CustomVSyncIntervalPercentageProxy)); + OnPropertyChanged(nameof(CustomVSyncIntervalPercentageText)); + OnPropertyChanged(); + } + } public bool EnablePptc { get; set; } public bool EnableLowPowerPptc { get; set; } public bool EnableInternetAccess { get; set; } @@ -484,7 +555,9 @@ namespace Ryujinx.Ava.UI.ViewModels CurrentDate = currentDateTime.Date; CurrentTime = currentDateTime.TimeOfDay; - EnableVsync = config.Graphics.EnableVsync; + EnableCustomVSyncInterval = config.Graphics.EnableCustomVSyncInterval.Value; + CustomVSyncInterval = config.Graphics.CustomVSyncInterval; + VSyncMode = config.Graphics.VSyncMode; EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; DramSize = config.System.DramSize; IgnoreMissingServices = config.System.IgnoreMissingServices; @@ -590,7 +663,9 @@ namespace Ryujinx.Ava.UI.ViewModels } config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds()); - config.Graphics.EnableVsync.Value = EnableVsync; + config.Graphics.VSyncMode.Value = VSyncMode; + config.Graphics.EnableCustomVSyncInterval.Value = EnableCustomVSyncInterval; + config.Graphics.CustomVSyncInterval.Value = CustomVSyncInterval; config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; config.System.DramSize.Value = DramSize; config.System.IgnoreMissingServices.Value = IgnoreMissingServices; @@ -660,6 +735,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.ToFileFormat().SaveConfig(Program.ConfigurationPath); MainWindow.UpdateGraphicsConfig(); + MainWindow.MainWindowViewModel.VSyncModeSettingChanged(); SaveSettingsEvent?.Invoke(); diff --git a/src/Ryujinx/UI/ViewModels/XCITrimmerViewModel.cs b/src/Ryujinx/UI/ViewModels/XCITrimmerViewModel.cs index b582360f1..e1f9eead5 100644 --- a/src/Ryujinx/UI/ViewModels/XCITrimmerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/XCITrimmerViewModel.cs @@ -33,7 +33,7 @@ namespace Ryujinx.Ava.UI.ViewModels private const string _FileExtXCI = "XCI"; private readonly Ryujinx.Common.Logging.XCIFileTrimmerLog _logger; - private readonly ApplicationLibrary _applicationLibrary; + private ApplicationLibrary ApplicationLibrary => _mainWindowViewModel.ApplicationLibrary; private Optional _processingApplication = null; private AvaloniaList _allXCIFiles = new(); private AvaloniaList _selectedXCIFiles = new(); @@ -47,15 +47,14 @@ namespace Ryujinx.Ava.UI.ViewModels public XCITrimmerViewModel(MainWindowViewModel mainWindowViewModel) { - _logger = new XCIFileTrimmerWindowLog(this); + _logger = new XCITrimmerLog.TrimmerWindow(this); _mainWindowViewModel = mainWindowViewModel; - _applicationLibrary = _mainWindowViewModel.ApplicationLibrary; LoadXCIApplications(); } private void LoadXCIApplications() { - var apps = _applicationLibrary.Applications.Items + var apps = ApplicationLibrary.Applications.Items .Where(app => app.FileExtension == _FileExtXCI); foreach (var xciApp in apps) @@ -68,7 +67,7 @@ namespace Ryujinx.Ava.UI.ViewModels string path, OperationOutcome operationOutcome = OperationOutcome.Undetermined) { - var xciApp = _applicationLibrary.Applications.Items.First(app => app.FileExtension == _FileExtXCI && app.Path == path); + var xciApp = ApplicationLibrary.Applications.Items.First(app => app.FileExtension == _FileExtXCI && app.Path == path); return XCITrimmerFileModel.FromApplicationData(xciApp, _logger) with { ProcessingOutcome = operationOutcome }; } @@ -538,4 +537,4 @@ namespace Ryujinx.Ava.UI.ViewModels } } } -} \ No newline at end of file +} diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index 883bf8971..ff56a4681 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -14,14 +14,14 @@ + Source="resm:Ryujinx.UI.Common.Resources.Logo_Thiccjinx.png?assembly=Ryujinx.UI.Common" /> @@ -58,7 +58,7 @@ @@ -260,6 +260,10 @@ IsEnabled="{Binding IsGameRunning}" /> + + + + @@ -286,6 +290,25 @@ Icon="{ext:Icon mdi-update}" ToolTip.Tip="{ext:Locale CheckUpdatesTooltip}" /> + + + + { - ViewModel.WindowState = WindowState.Normal; Window.Arrange(new Rect(Window.Position.X, Window.Position.Y, windowWidthScaled, windowHeightScaled)); @@ -210,7 +219,13 @@ namespace Ryujinx.Ava.UI.Views.Main public async void CheckForUpdates(object sender, RoutedEventArgs e) { if (Updater.CanUpdate(true)) - await Window.BeginUpdateAsync(true); + await Updater.BeginUpdateAsync(true); + } + + private void MenuItem_OnClick(object sender, RoutedEventArgs e) + { + if (sender is MenuItem { Tag: string url }) + OpenHelper.OpenUrl(url); } public async void OpenXCITrimmerWindow(object sender, RoutedEventArgs e) => await XCITrimmerWindow.Show(ViewModel); diff --git a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml index 0e0526f49..6e72a8b4b 100644 --- a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml @@ -23,7 +23,7 @@ Background="{DynamicResource ThemeContentBackgroundColor}" DockPanel.Dock="Bottom" IsVisible="{Binding ShowMenuAndStatusBar}" - ColumnDefinitions="Auto,Auto,*,Auto"> + ColumnDefinitions="Auto,Auto,*,Auto,Auto"> + PointerReleased="VSyncMode_PointerReleased" + Text="{Binding VSyncModeText}" + TextAlignment="Start"/> + + + + + IsVisible="{Binding ShowShaderCompilationHint}" /> + + - - - + IsVisible="{Binding IsGameRunning}" /> diff --git a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs index fd413d2f9..dd4ed8297 100644 --- a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs +++ b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs @@ -38,11 +38,10 @@ namespace Ryujinx.Ava.UI.Views.Main } } - private void VsyncStatus_PointerReleased(object sender, PointerReleasedEventArgs e) + private void VSyncMode_PointerReleased(object sender, PointerReleasedEventArgs e) { - Window.ViewModel.AppHost.ToggleVSync(); - - Logger.Info?.Print(LogClass.Application, $"VSync toggled to: {Window.ViewModel.AppHost.Device.EnableDeviceVsync}"); + Window.ViewModel.ToggleVSyncMode(); + Logger.Info?.Print(LogClass.Application, $"VSync Mode toggled to: {Window.ViewModel.AppHost.Device.VSyncMode}"); } private void DockedStatus_PointerReleased(object sender, PointerReleasedEventArgs e) diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml index 06f6728da..da0957e02 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml @@ -1,4 +1,4 @@ - - - - + + + @@ -103,6 +103,18 @@ + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs index fb0fe2bb1..609f61633 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs +++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs @@ -82,8 +82,8 @@ namespace Ryujinx.Ava.UI.Views.Settings switch (button.Name) { - case "ToggleVsync": - viewModel.KeyboardHotkey.ToggleVsync = buttonValue.AsHidType(); + case "ToggleVSyncMode": + viewModel.KeyboardHotkey.ToggleVSyncMode = buttonValue.AsHidType(); break; case "Screenshot": viewModel.KeyboardHotkey.Screenshot = buttonValue.AsHidType(); @@ -109,6 +109,12 @@ namespace Ryujinx.Ava.UI.Views.Settings case "VolumeDown": viewModel.KeyboardHotkey.VolumeDown = buttonValue.AsHidType(); break; + case "CustomVSyncIntervalIncrement": + viewModel.KeyboardHotkey.CustomVSyncIntervalIncrement = buttonValue.AsHidType(); + break; + case "CustomVSyncIntervalDecrement": + viewModel.KeyboardHotkey.CustomVSyncIntervalDecrement = buttonValue.AsHidType(); + break; } } }; diff --git a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml index 4fe57b425..e04e541c3 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml @@ -4,6 +4,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" @@ -181,11 +182,68 @@ Width="350" ToolTip.Tip="{ext:Locale TimeTooltip}" /> - + - + VerticalAlignment="Center" + Text="{ext:Locale SettingsTabSystemVSyncMode}" + ToolTip.Tip="{ext:Locale SettingsTabSystemVSyncModeTooltip}" + Width="250" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Windows/AboutWindow.axaml b/src/Ryujinx/UI/Windows/AboutWindow.axaml index 6d4a7b7e3..c5abb0241 100644 --- a/src/Ryujinx/UI/Windows/AboutWindow.axaml +++ b/src/Ryujinx/UI/Windows/AboutWindow.axaml @@ -6,8 +6,10 @@ xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewModel="clr-namespace:Ryujinx.Ava.UI.ViewModels" - Width="550" - Height="260" + MinWidth="550" + MinHeight="260" + MaxWidth="600" + MaxHeight="500" Margin="0,-12,0,0" d:DesignHeight="260" d:DesignWidth="550" @@ -34,7 +36,8 @@ HorizontalAlignment="Center" Spacing="10"> @@ -163,7 +166,16 @@ Text="{ext:Locale AboutRyujinxMaintainersTitle}" /> + +