mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-26 12:21:03 +00:00
Compare commits
19 Commits
v3.7.1
...
chore/upda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a278dc614 | ||
|
|
214e8f9538 | ||
|
|
a7b5bdb3b4 | ||
|
|
99e34ce060 | ||
|
|
f0421d9fe0 | ||
|
|
ca35da37ed | ||
|
|
7435bff64f | ||
|
|
864fd282f0 | ||
|
|
945173f48e | ||
|
|
0d60ec8801 | ||
|
|
0575e837c8 | ||
|
|
5ff15b30b2 | ||
|
|
2f1185bbf9 | ||
|
|
19a57cb1e0 | ||
|
|
bbd9ff76c4 | ||
|
|
39e76f458f | ||
|
|
393c55738c | ||
|
|
24f7ecb795 | ||
|
|
97b27a1785 |
120
.github/workflows/update-aur.yml
vendored
Normal file
120
.github/workflows/update-aur.yml
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
name: Update AUR Package
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-aur:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: archlinux:latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout main repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
pacman -Syu --noconfirm
|
||||||
|
pacman -S --noconfirm nodejs npm git base-devel
|
||||||
|
|
||||||
|
- name: Get version to update
|
||||||
|
id: get-version
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "release" ]; then
|
||||||
|
# Remove 'v' prefix if present
|
||||||
|
VERSION="${{ github.event.release.tag_name }}"
|
||||||
|
VERSION="${VERSION#v}"
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
echo "source=release" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
# Get latest release version
|
||||||
|
VERSION=$(curl -s https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r '.tag_name' | sed 's/^v//')
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
echo "source=latest" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
echo "Version to update: $VERSION"
|
||||||
|
|
||||||
|
- name: Setup SSH for AUR
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.AUR_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||||
|
chmod 600 ~/.ssh/id_rsa
|
||||||
|
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
|
||||||
|
eval "$(ssh-agent -s)"
|
||||||
|
ssh-add ~/.ssh/id_rsa
|
||||||
|
|
||||||
|
- name: Clone AUR repository
|
||||||
|
run: |
|
||||||
|
git clone ssh://aur@aur.archlinux.org/hydra-launcher-bin.git
|
||||||
|
|
||||||
|
- name: Check if update is needed
|
||||||
|
id: check-update
|
||||||
|
run: |
|
||||||
|
cd hydra-launcher-bin
|
||||||
|
CURRENT_VERSION=$(grep '^pkgver=' hydra-launcher-bin/PKGBUILD | cut -d'=' -f2)
|
||||||
|
NEW_VERSION="${{ steps.get-version.outputs.version }}"
|
||||||
|
|
||||||
|
echo "Current AUR version: $CURRENT_VERSION"
|
||||||
|
echo "New version: $NEW_VERSION"
|
||||||
|
|
||||||
|
if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
|
||||||
|
echo "update_needed=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "No update needed - versions are the same"
|
||||||
|
else
|
||||||
|
echo "update_needed=true" >> $GITHUB_OUTPUT
|
||||||
|
echo "Update needed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Update PKGBUILD and .SRCINFO
|
||||||
|
if: steps.check-update.outputs.update_needed == 'true'
|
||||||
|
run: |
|
||||||
|
cd hydra-launcher-bin
|
||||||
|
node ../scripts/update-pkgver.js "${{ steps.get-version.outputs.version }}" ./PKGBUILD
|
||||||
|
updpkgsums
|
||||||
|
makepkg --printsrcinfo > .SRCINFO
|
||||||
|
|
||||||
|
- name: Configure Git
|
||||||
|
if: steps.check-update.outputs.update_needed == 'true'
|
||||||
|
run: |
|
||||||
|
cd hydra-launcher-bin
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
- name: Commit and push changes
|
||||||
|
if: steps.check-update.outputs.update_needed == 'true'
|
||||||
|
run: |
|
||||||
|
cd hydra-launcher-bin
|
||||||
|
git add PKGBUILD .SRCINFO
|
||||||
|
|
||||||
|
if git diff --staged --quiet; then
|
||||||
|
echo "No changes to commit"
|
||||||
|
else
|
||||||
|
COMMIT_MSG="Update to ${{ steps.get-version.outputs.version }}"
|
||||||
|
if [ "${{ steps.get-version.outputs.source }}" = "release" ]; then
|
||||||
|
COMMIT_MSG="$COMMIT_MSG (automated release update)"
|
||||||
|
else
|
||||||
|
COMMIT_MSG="$COMMIT_MSG (latest release)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
git commit -m "$COMMIT_MSG"
|
||||||
|
git push origin master
|
||||||
|
echo "Successfully updated AUR package to version ${{ steps.get-version.outputs.version }}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Create summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "## AUR Update Summary" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- **Version**: ${{ steps.get-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- **Source**: ${{ steps.get-version.outputs.source }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- **Update needed**: ${{ steps.check-update.outputs.update_needed }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "${{ steps.check-update.outputs.update_needed }}" = "true" ]; then
|
||||||
|
echo "- **Status**: ✅ AUR package updated successfully" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "- **Status**: ⏭️ No update needed" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
32
scripts/update-pkgver.js
Executable file
32
scripts/update-pkgver.js
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
const fs = require("node:fs");
|
||||||
|
|
||||||
|
function updatePkgver(newVersion, pkgbuildPath) {
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(pkgbuildPath, "utf8");
|
||||||
|
const lines = content.split("\n");
|
||||||
|
|
||||||
|
const updatedLines = lines.map((line) => {
|
||||||
|
if (line.trim().startsWith("pkgver=")) {
|
||||||
|
return `pkgver=${newVersion}`;
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(pkgbuildPath, updatedLines.join("\n"), "utf8");
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`✅ Successfully updated pkgver to ${newVersion} in ${pkgbuildPath}`
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Error updating pkgver: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get version from command line arguments
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
const newVersion = args[0];
|
||||||
|
const pkgbuildPath = args[1] || "./PKGBUILD";
|
||||||
|
|
||||||
|
updatePkgver(newVersion, pkgbuildPath);
|
||||||
@@ -357,7 +357,11 @@
|
|||||||
"delete_review_modal_description": "This action cannot be undone.",
|
"delete_review_modal_description": "This action cannot be undone.",
|
||||||
"delete_review_modal_delete_button": "Delete",
|
"delete_review_modal_delete_button": "Delete",
|
||||||
"delete_review_modal_cancel_button": "Cancel",
|
"delete_review_modal_cancel_button": "Cancel",
|
||||||
"vote_failed": "Failed to register your vote. Please try again."
|
"vote_failed": "Failed to register your vote. Please try again.",
|
||||||
|
"show_original": "Show original",
|
||||||
|
"show_translation": "Show translation",
|
||||||
|
"show_original_translated_from": "Show original (translated from {{language}})",
|
||||||
|
"hide_original": "Hide original"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Activate Hydra",
|
"title": "Activate Hydra",
|
||||||
|
|||||||
708
src/locales/fi/translation.json
Normal file
708
src/locales/fi/translation.json
Normal file
@@ -0,0 +1,708 @@
|
|||||||
|
{
|
||||||
|
"language_name": "Suomi",
|
||||||
|
"app": {
|
||||||
|
"successfully_signed_in": "Kirjautuminen onnistui"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"surprise_me": "Yllätä minut",
|
||||||
|
"no_results": "Ei tuloksia",
|
||||||
|
"start_typing": "Aloitan kirjoittamisen...",
|
||||||
|
"hot": "Suosittua nyt",
|
||||||
|
"weekly": "📅 Viikon parhaat pelit",
|
||||||
|
"achievements": "🏆 Pelit saavutuksilla"
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"catalogue": "Katalogi",
|
||||||
|
"downloads": "Lataukset",
|
||||||
|
"settings": "Asetukset",
|
||||||
|
"my_library": "Kirjasto",
|
||||||
|
"downloading_metadata": "{{title}} (Metatietojen lataus…)",
|
||||||
|
"paused": "{{title}} (Keskeytetty)",
|
||||||
|
"downloading": "{{title}} ({{percentage}} - Lataa…)",
|
||||||
|
"filter": "Hae",
|
||||||
|
"home": "Koti",
|
||||||
|
"queued": "{{title}} (Jonossa)",
|
||||||
|
"game_has_no_executable": "Pelin käynnistystiedostoa ei ole valittu",
|
||||||
|
"sign_in": "Kirjaudu sisään",
|
||||||
|
"friends": "Kaverit",
|
||||||
|
"need_help": "Tarvitsetko apua?",
|
||||||
|
"favorites": "Suosikit",
|
||||||
|
"playable_button_title": "Näytä vain asennetut pelit.",
|
||||||
|
"add_custom_game_tooltip": "Lisää mukautettu peli",
|
||||||
|
"show_playable_only_tooltip": "Näytä vain pelattavissa olevat",
|
||||||
|
"custom_game_modal": "Lisää mukautettu peli",
|
||||||
|
"custom_game_modal_description": "Lisää mukautettu peli kirjastoon valitsemalla suoritettava tiedosto",
|
||||||
|
"custom_game_modal_executable_path": "Suoritettavan tiedoston polku",
|
||||||
|
"custom_game_modal_select_executable": "Valitse suoritettava tiedosto",
|
||||||
|
"custom_game_modal_title": "Pelin nimi",
|
||||||
|
"custom_game_modal_enter_title": "Syötä pelin nimi",
|
||||||
|
"custom_game_modal_browse": "Selaa",
|
||||||
|
"custom_game_modal_cancel": "Peruuta",
|
||||||
|
"custom_game_modal_add": "Lisää peli",
|
||||||
|
"custom_game_modal_adding": "Lisätään peliä...",
|
||||||
|
"custom_game_modal_success": "Mukautettu peli lisätty onnistuneesti",
|
||||||
|
"custom_game_modal_failed": "Mukautetun pelin lisääminen epäonnistui",
|
||||||
|
"custom_game_modal_executable": "Suoritettava tiedosto",
|
||||||
|
"edit_game_modal": "Mukauta resursseja",
|
||||||
|
"edit_game_modal_description": "Mukauta pelin resursseja ja tietoja",
|
||||||
|
"edit_game_modal_title": "Nimi",
|
||||||
|
"edit_game_modal_enter_title": "Syötä nimi",
|
||||||
|
"edit_game_modal_image": "Kuva",
|
||||||
|
"edit_game_modal_select_image": "Valitse kuva",
|
||||||
|
"edit_game_modal_browse": "Selaa",
|
||||||
|
"edit_game_modal_image_preview": "Kuvan esikatselu",
|
||||||
|
"edit_game_modal_icon": "Kuvake",
|
||||||
|
"edit_game_modal_select_icon": "Valitse kuvake",
|
||||||
|
"edit_game_modal_icon_preview": "Kuvakkeen esikatselu",
|
||||||
|
"edit_game_modal_logo": "Logo",
|
||||||
|
"edit_game_modal_select_logo": "Valitse logo",
|
||||||
|
"edit_game_modal_logo_preview": "Logon esikatselu",
|
||||||
|
"edit_game_modal_hero": "Pelin kansikuva",
|
||||||
|
"edit_game_modal_select_hero": "Valitse pelin kansikuva",
|
||||||
|
"edit_game_modal_hero_preview": "Kansikuvan esikatselu",
|
||||||
|
"edit_game_modal_cancel": "Peruuta",
|
||||||
|
"edit_game_modal_update": "Päivitä",
|
||||||
|
"edit_game_modal_updating": "Päivitetään...",
|
||||||
|
"edit_game_modal_fill_required": "Täytä kaikki pakolliset kentät",
|
||||||
|
"edit_game_modal_success": "Resurssit päivitetty onnistuneesti",
|
||||||
|
"edit_game_modal_failed": "Resurssien päivitys epäonnistui",
|
||||||
|
"edit_game_modal_image_filter": "Kuva",
|
||||||
|
"edit_game_modal_icon_resolution": "Suositeltu resoluutio: 256x256px",
|
||||||
|
"edit_game_modal_logo_resolution": "Suositeltu resoluutio: 640x360px",
|
||||||
|
"edit_game_modal_hero_resolution": "Suositeltu resoluutio: 1920x620px",
|
||||||
|
"edit_game_modal_assets": "Resurssit",
|
||||||
|
"edit_game_modal_drop_icon_image_here": "Pudota kuvakkeen kuva tähän",
|
||||||
|
"edit_game_modal_drop_logo_image_here": "Pudota logon kuva tähän",
|
||||||
|
"edit_game_modal_drop_hero_image_here": "Pudota kansikuvan kuva tähän",
|
||||||
|
"edit_game_modal_drop_to_replace_icon": "Pudota korvataksesi kuvake",
|
||||||
|
"edit_game_modal_drop_to_replace_logo": "Pudota korvataksesi logo",
|
||||||
|
"edit_game_modal_drop_to_replace_hero": "Pudota korvataksesi kansikuva",
|
||||||
|
"install_decky_plugin": "Asenna Decky-lisäosa",
|
||||||
|
"update_decky_plugin": "Päivitä Decky-lisäosa",
|
||||||
|
"decky_plugin_installed_version": "Decky-lisäosa (v{{version}})",
|
||||||
|
"install_decky_plugin_title": "Asenna Hydra Decky -lisäosa",
|
||||||
|
"install_decky_plugin_message": "Tämä lataa ja asentaa Hydra-lisäosan Decky Loaderiin. Saattaa vaatia korotetut oikeudet. Jatketaanko?",
|
||||||
|
"update_decky_plugin_title": "Päivitä Hydra Decky -lisäosa",
|
||||||
|
"update_decky_plugin_message": "Uusi Hydra Decky -lisäosan versio on saatavilla. Haluatko päivittää sen nyt?",
|
||||||
|
"decky_plugin_installed": "Decky-lisäosa v{{version}} asennettu onnistuneesti",
|
||||||
|
"decky_plugin_installation_failed": "Decky-lisäosan asennus epäonnistui: {{error}}",
|
||||||
|
"decky_plugin_installation_error": "Decky-lisäosan asennusvirhe: {{error}}",
|
||||||
|
"confirm": "Vahvista",
|
||||||
|
"cancel": "Peruuta"
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"search": "Hae",
|
||||||
|
"home": "Koti",
|
||||||
|
"catalogue": "Katalogi",
|
||||||
|
"downloads": "Lataukset",
|
||||||
|
"search_results": "Hakutulokset",
|
||||||
|
"settings": "Asetukset",
|
||||||
|
"version_available_install": "Versio {{version}} saatavilla. Asentaaksesi napsauta tästä.",
|
||||||
|
"version_available_download": "Versio {{version}} saatavilla. Ladataaksesi napsauta tästä."
|
||||||
|
},
|
||||||
|
"bottom_panel": {
|
||||||
|
"no_downloads_in_progress": "Ei meneillään olevia latauksia",
|
||||||
|
"downloading_metadata": "Ladataan metatietoja {{title}}…",
|
||||||
|
"downloading": "Ladataan {{title}}… ({{percentage}} valmis) - Lopetus {{eta}} - {{speed}}",
|
||||||
|
"calculating_eta": "Ladataan {{title}}… ({{percentage}} valmis) - Lasketaan jäljellä olevaa aikaa…",
|
||||||
|
"checking_files": "Tarkistetaan tiedostoja {{title}}… ({{percentage}} valmis)",
|
||||||
|
"installing_common_redist": "{{log}}…",
|
||||||
|
"installation_complete": "Asennus valmis",
|
||||||
|
"installation_complete_message": "Kirjastot asennettu onnistuneesti"
|
||||||
|
},
|
||||||
|
"catalogue": {
|
||||||
|
"search": "Suodatin…",
|
||||||
|
"developers": "Kehittäjät",
|
||||||
|
"genres": "Genret",
|
||||||
|
"tags": "Tagit",
|
||||||
|
"publishers": "Julkaisijat",
|
||||||
|
"download_sources": "Latauslähteet",
|
||||||
|
"result_count": "{{resultCount}} tulosta",
|
||||||
|
"filter_count": "{{filterCount}} saatavilla",
|
||||||
|
"clear_filters": "Tyhjennä {{filterCount}} valittua"
|
||||||
|
},
|
||||||
|
"game_details": {
|
||||||
|
"open_download_options": "Avaa lähteet",
|
||||||
|
"download_options_zero": "Ei lähteitä",
|
||||||
|
"download_options_one": "{{count}} lähde",
|
||||||
|
"download_options_other": "{{count}} lähdettä",
|
||||||
|
"updated_at": "Päivitetty {{updated_at}}",
|
||||||
|
"install": "Asenna",
|
||||||
|
"resume": "Jatka",
|
||||||
|
"pause": "Keskeytä",
|
||||||
|
"cancel": "Peruuta",
|
||||||
|
"remove": "Poista",
|
||||||
|
"space_left_on_disk": "{{space}} vapaana levyltä",
|
||||||
|
"eta": "Lopetus {{eta}}",
|
||||||
|
"calculating_eta": "Lasketaan jäljellä olevaa aikaa…",
|
||||||
|
"downloading_metadata": "Ladataan metatietoja…",
|
||||||
|
"filter": "Hae repackeja",
|
||||||
|
"requirements": "Järjestelmävaatimukset",
|
||||||
|
"minimum": "Minimi",
|
||||||
|
"recommended": "Suositeltu",
|
||||||
|
"paused": "Keskeytetty",
|
||||||
|
"release_date": "Julkaistu {{date}}",
|
||||||
|
"publisher": "Julkaisija {{publisher}}",
|
||||||
|
"hours": "tuntia",
|
||||||
|
"minutes": "minuuttia",
|
||||||
|
"amount_hours": "{{amount}} tuntia",
|
||||||
|
"amount_minutes": "{{amount}} minuuttia",
|
||||||
|
"accuracy": "tarkkuus {{accuracy}}%",
|
||||||
|
"add_to_library": "Lisää kirjastoon",
|
||||||
|
"already_in_library": "Jo kirjastossa",
|
||||||
|
"remove_from_library": "Poista kirjastosta",
|
||||||
|
"no_downloads": "Ei saatavilla olevia lähteitä",
|
||||||
|
"play_time": "Pelattu {{amount}}",
|
||||||
|
"last_time_played": "Viimeksi pelattu {{period}}",
|
||||||
|
"not_played_yet": "Et ole vielä pelannut {{title}}",
|
||||||
|
"next_suggestion": "Seuraava ehdotus",
|
||||||
|
"play": "Pelaa",
|
||||||
|
"deleting": "Poistetaan asennustiedostoa…",
|
||||||
|
"close": "Sulje",
|
||||||
|
"playing_now": "Käynnissä",
|
||||||
|
"change": "Vaihda",
|
||||||
|
"repacks_modal_description": "Valitse repack ladattavaksi",
|
||||||
|
"select_folder_hint": "Vaihtaaksesi oletuslatauskansiota, avaa <0>Asetukset</0>",
|
||||||
|
"download_now": "Lataa nyt",
|
||||||
|
"no_shop_details": "Kuvausta ei saatu",
|
||||||
|
"download_options": "Lähteet",
|
||||||
|
"download_path": "Latauspolku",
|
||||||
|
"previous_screenshot": "Edellinen kuvakaappaus",
|
||||||
|
"next_screenshot": "Seuraava kuvakaappaus",
|
||||||
|
"screenshot": "Kuvakaappaus {{number}}",
|
||||||
|
"open_screenshot": "Avaa kuvakaappaus {{number}}",
|
||||||
|
"download_settings": "Latausasetukset",
|
||||||
|
"downloader": "Lataaja",
|
||||||
|
"select_executable": "Valitse",
|
||||||
|
"no_executable_selected": "Tiedostoa ei valittu",
|
||||||
|
"open_folder": "Avaa kansio",
|
||||||
|
"open_download_location": "Selaa latauskansio",
|
||||||
|
"create_shortcut": "Luo työpöydän pikakuvake",
|
||||||
|
"create_shortcut_simple": "Luo pikakuvake",
|
||||||
|
"clear": "Tyhjennä",
|
||||||
|
"remove_files": "Poista tiedostot",
|
||||||
|
"remove_from_library_title": "Oletko varma?",
|
||||||
|
"remove_from_library_description": "{{game}} poistetaan kirjastostasi.",
|
||||||
|
"options": "Asetukset",
|
||||||
|
"properties": "Ominaisuudet",
|
||||||
|
"executable_section_title": "Tiedosto",
|
||||||
|
"executable_section_description": "Polku tiedostoon, joka käynnistetään kun painat \"Pelaa\"",
|
||||||
|
"downloads_section_title": "Lataukset",
|
||||||
|
"downloads_section_description": "Tarkista päivitysten tai muiden peliversioiden saatavuus",
|
||||||
|
"danger_zone_section_title": "Vaaravyöhyke",
|
||||||
|
"danger_zone_section_description": "Voit poistaa tämän pelin kirjastostasi tai Hydrasta ladatut tiedostot",
|
||||||
|
"download_in_progress": "Lataus käynnissä",
|
||||||
|
"download_paused": "Lataus keskeytetty",
|
||||||
|
"last_downloaded_option": "Viimeisin latausvaihtoehto",
|
||||||
|
"create_steam_shortcut": "Luo Steam-pikakuvake",
|
||||||
|
"create_shortcut_success": "Pikakuvake luotu",
|
||||||
|
"you_might_need_to_restart_steam": "Saattaa olla, että sinun on käynnistettävä Steam uudelleen nähdäksesi muutokset",
|
||||||
|
"create_shortcut_error": "Pikakuvakkeen luonti epäonnistui",
|
||||||
|
"add_to_favorites": "Lisää suosikkeihin",
|
||||||
|
"remove_from_favorites": "Poista suosikeista",
|
||||||
|
"failed_update_favorites": "Suosikkien päivitys epäonnistui",
|
||||||
|
"game_removed_from_library": "Peli poistettu kirjastosta",
|
||||||
|
"failed_remove_from_library": "Poistaminen kirjastosta epäonnistui",
|
||||||
|
"files_removed_success": "Tiedostot poistettu onnistuneesti",
|
||||||
|
"failed_remove_files": "Tiedostojen poisto epäonnistui",
|
||||||
|
"nsfw_content_title": "Tämä peli sisältää sopimatonta sisältöä",
|
||||||
|
"nsfw_content_description": "{{title}} sisältää sisältöä, joka ei välttämättä sovellu kaikenikäisille. \nOletko varma, että haluat jatkaa?",
|
||||||
|
"allow_nsfw_content": "Jatka",
|
||||||
|
"refuse_nsfw_content": "Takaisin",
|
||||||
|
"stats": "Tilastot",
|
||||||
|
"download_count": "Lataukset",
|
||||||
|
"player_count": "Aktiiviset pelaajat",
|
||||||
|
"download_error": "Tämä latausvaihtoehto ei ole saatavilla",
|
||||||
|
"download": "Lataa",
|
||||||
|
"executable_path_in_use": "Suoritettavaa tiedostoa käyttää jo \"{{game}}\"",
|
||||||
|
"warning": "Varoitus:",
|
||||||
|
"hydra_needs_to_remain_open": "Tämän latauksen aikana Hydran on pysyttävä auki, kunnes se on valmis. Jos Hydra sulkeutuu ennen valmistumista, menetät edistymisen.",
|
||||||
|
"achievements": "Saavutukset",
|
||||||
|
"achievements_count": "Saavutukset {{unlockedCount}}/{{achievementsCount}}",
|
||||||
|
"show_more": "Näytä enemmän",
|
||||||
|
"show_less": "Näytä vähemmän",
|
||||||
|
"reviews": "Arvostelut",
|
||||||
|
"leave_a_review": "Jätä arvostelu",
|
||||||
|
"write_review_placeholder": "Jaa ajatuksesi tästä pelistä...",
|
||||||
|
"sort_newest": "Uusimmat ensin",
|
||||||
|
"no_reviews_yet": "Ei vielä arvosteluja",
|
||||||
|
"be_first_to_review": "Ole ensimmäinen, joka jakaa ajatuksensa tästä pelistä!",
|
||||||
|
"sort_oldest": "Vanhimmat ensin",
|
||||||
|
"sort_highest_score": "Korkein pistemäärä",
|
||||||
|
"sort_lowest_score": "Matalin pistemäärä",
|
||||||
|
"sort_most_voted": "Eniten äänestetyt",
|
||||||
|
"rating": "Arvio",
|
||||||
|
"rating_stats": "Arvio",
|
||||||
|
"rating_very_negative": "Erittäin negatiivinen",
|
||||||
|
"rating_negative": "Negatiivinen",
|
||||||
|
"rating_neutral": "Neutraali",
|
||||||
|
"rating_positive": "Positiivinen",
|
||||||
|
"rating_very_positive": "Erittäin positiivinen",
|
||||||
|
"submit_review": "Lähetä",
|
||||||
|
"submitting": "Lähetetään...",
|
||||||
|
"review_submitted_successfully": "Arvostelu lähetetty onnistuneesti!",
|
||||||
|
"review_submission_failed": "Arvostelun lähettäminen epäonnistui. Yritä uudelleen.",
|
||||||
|
"review_cannot_be_empty": "Arvostelun tekstikenttä ei voi olla tyhjä.",
|
||||||
|
"review_deleted_successfully": "Arvostelu poistettu onnistuneesti.",
|
||||||
|
"review_deletion_failed": "Arvostelun poisto epäonnistui. Yritä uudelleen.",
|
||||||
|
"loading_reviews": "Ladataan arvosteluja...",
|
||||||
|
"loading_more_reviews": "Ladataan lisää arvosteluja...",
|
||||||
|
"load_more_reviews": "Lataa lisää arvosteluja",
|
||||||
|
"you_seemed_to_enjoy_this_game": "Näyttää siltä, että nautit tästä pelistä",
|
||||||
|
"would_you_recommend_this_game": "Haluatko jättää arvion tästä pelistä?",
|
||||||
|
"yes": "Kyllä",
|
||||||
|
"maybe_later": "Ehkä myöhemmin",
|
||||||
|
"rating_count": "Arvio",
|
||||||
|
"delete_review": "Poista arvostelu",
|
||||||
|
"remove_review": "Poista arvostelu",
|
||||||
|
"delete_review_modal_title": "Haluatko varmasti poistaa arvostelusi?",
|
||||||
|
"delete_review_modal_description": "Tätä toimintoa ei voi peruuttaa.",
|
||||||
|
"delete_review_modal_delete_button": "Poista",
|
||||||
|
"delete_review_modal_cancel_button": "Peruuta",
|
||||||
|
"show_original": "Näytä alkuperäinen",
|
||||||
|
"show_translation": "Näytä käännös",
|
||||||
|
"show_original_translated_from": "Näytä alkuperäinen (käännös kielestä {{language}})",
|
||||||
|
"hide_original": "Piilota alkuperäinen",
|
||||||
|
"cloud_save": "Pilvitallennus",
|
||||||
|
"cloud_save_description": "Tallenna edistymisesi pilveen ja jatka pelaamista millä tahansa laitteella",
|
||||||
|
"backups": "Varmuuskopiot",
|
||||||
|
"install_backup": "Asenna",
|
||||||
|
"delete_backup": "Poista",
|
||||||
|
"create_backup": "Luo uusi varmuuskopio",
|
||||||
|
"last_backup_date": "Viimeisin varmuuskopio {{date}}",
|
||||||
|
"no_backup_preview": "Tallennuksia ei löytynyt tälle otsikolle",
|
||||||
|
"restoring_backup": "Palautetaan varmuuskopiota ({{progress}} valmis)…",
|
||||||
|
"uploading_backup": "Ladataan varmuuskopiota…",
|
||||||
|
"no_backups": "Et ole vielä luonut varmuuskopioita tästä pelistä",
|
||||||
|
"backup_uploaded": "Varmuuskopio ladattu",
|
||||||
|
"backup_failed": "Varmuuskopiointi epäonnistui",
|
||||||
|
"backup_deleted": "Varmuuskopio poistettu",
|
||||||
|
"backup_restored": "Varmuuskopio palautettu",
|
||||||
|
"see_all_achievements": "Näytä kaikki saavutukset",
|
||||||
|
"sign_in_to_see_achievements": "Kirjaudu sisään nähdäksesi saavutukset",
|
||||||
|
"mapping_method_automatic": "Automaattinen",
|
||||||
|
"mapping_method_manual": "Manuaalinen",
|
||||||
|
"mapping_method_label": "Kartoitusmenetelmä",
|
||||||
|
"files_automatically_mapped": "Tiedostot kartoitetu automaattisesti",
|
||||||
|
"no_backups_created": "Tälle pelille ei ole luotu varmuuskopioita",
|
||||||
|
"manage_files": "Hallitse tiedostoja",
|
||||||
|
"loading_save_preview": "Etsitään tallennuksia…",
|
||||||
|
"wine_prefix": "Wine-etuliite",
|
||||||
|
"wine_prefix_description": "Tässä pelissä käytettävä Wine-etuliite",
|
||||||
|
"launch_options": "Käynnistysvalinnat",
|
||||||
|
"launch_options_description": "Edistyneet käyttäjät voivat tehdä muutoksia käynnistysvalintoihin",
|
||||||
|
"launch_options_placeholder": "Valintaa ei määritetty",
|
||||||
|
"no_download_option_info": "Tietoja ei saatavilla",
|
||||||
|
"backup_deletion_failed": "Varmuuskopion poisto epäonnistui",
|
||||||
|
"max_number_of_artifacts_reached": "Tämän pelin enimmäismäärä varmuuskopioita saavutettu",
|
||||||
|
"achievements_not_sync": "Saavutuksesi eivät ole synkronoidut",
|
||||||
|
"manage_files_description": "Hallitse tallennettavia ja palautettavia tiedostoja",
|
||||||
|
"select_folder": "Valitse kansio",
|
||||||
|
"backup_from": "Varmuuskopio {{date}}",
|
||||||
|
"automatic_backup_from": "Automaattinen varmuuskopio {{date}}",
|
||||||
|
"enable_automatic_cloud_sync": "Ota automaattinen pilvisynkronointi käyttöön",
|
||||||
|
"custom_backup_location_set": "Mukautettu varmuuskopiosijainti asetettu",
|
||||||
|
"no_directory_selected": "Hakemistoa ei valittu",
|
||||||
|
"no_write_permission": "Ei voi ladata tähän hakemistoon. Napsauta tästä saadaksesi lisätietoja.",
|
||||||
|
"reset_achievements": "Nollaa saavutukset",
|
||||||
|
"reset_achievements_description": "Tämä nollaa kaikki saavutukset pelille {{game}}",
|
||||||
|
"reset_achievements_title": "Oletko varma?",
|
||||||
|
"reset_achievements_success": "Saavutukset nollattu onnistuneesti",
|
||||||
|
"reset_achievements_error": "Saavutusten nollaus epäonnistui",
|
||||||
|
"download_error_gofile_quota_exceeded": "Olet ylittänyt Gofilen kuukausikiintiön. Odota, kunnes kiintiö palautuu.",
|
||||||
|
"download_error_real_debrid_account_not_authorized": "Real-Debrid -tilisi ei ole valtuutettu suorittamaan uusia latauksia. Tarkista tilin asetukset ja yritä uudelleen.",
|
||||||
|
"download_error_not_cached_on_real_debrid": "Tämä lataus ei ole saatavilla Real-Debridissä, eikä lataustilan hakeminen Real-Debridistä ole toistaiseksi mahdollista.",
|
||||||
|
"update_playtime_title": "Päivitä peliaika",
|
||||||
|
"update_playtime_description": "Päivitä pelin {{game}} peliaika manuaalisesti",
|
||||||
|
"update_playtime": "Päivitä peliaika",
|
||||||
|
"update_playtime_success": "Peliaika päivitetty onnistuneesti",
|
||||||
|
"update_playtime_error": "Peliajan päivitys epäonnistui",
|
||||||
|
"update_game_playtime": "Päivitä peliaika",
|
||||||
|
"manual_playtime_warning": "Pelituntisi merkitään manuaalisesti päivitetyiksi. Tätä toimintoa ei voi peruuttaa.",
|
||||||
|
"manual_playtime_tooltip": "Tämä peliaika on päivitetty manuaalisesti",
|
||||||
|
"download_error_not_cached_on_torbox": "Tämä lataus ei ole saatavilla TorBoxissa, eikä lataustilan hakeminen TorBoxista ole toistaiseksi mahdollista.",
|
||||||
|
"download_error_not_cached_on_hydra": "Tämä lataus ei ole saatavilla Nimbuksessa.",
|
||||||
|
"game_removed_from_favorites": "Peli poistettu suosikeista",
|
||||||
|
"game_added_to_favorites": "Peli lisätty suosikkeihin",
|
||||||
|
"game_removed_from_pinned": "Peli poistettu kiinnitetyistä",
|
||||||
|
"game_added_to_pinned": "Peli lisätty kiinnitettyihin",
|
||||||
|
"automatically_extract_downloaded_files": "Pura ladatut tiedostot automaattisesti",
|
||||||
|
"create_start_menu_shortcut": "Luo Käynnistä-valikon pikakuvake",
|
||||||
|
"invalid_wine_prefix_path": "Virheellinen Wine-etuliitteen polku",
|
||||||
|
"invalid_wine_prefix_path_description": "Wine-etuliitteen polku on virheellinen. Tarkista polku ja yritä uudelleen.",
|
||||||
|
"missing_wine_prefix": "Wine-etuliite vaaditaan varmuuskopiointiin Linuxissa",
|
||||||
|
"artifact_renamed": "Varmuuskopio nimettiin uudelleen onnistuneesti",
|
||||||
|
"rename_artifact": "Nimeä varmuuskopio uudelleen",
|
||||||
|
"rename_artifact_description": "Anna varmuuskopiolle kuvaavampi nimi.",
|
||||||
|
"artifact_name_label": "Varmuuskopion nimi",
|
||||||
|
"artifact_name_placeholder": "Syötä nimi varmuuskopiolle",
|
||||||
|
"save_changes": "Tallenna muutokset",
|
||||||
|
"required_field": "Tämä kenttä on pakollinen",
|
||||||
|
"max_length_field": "Tämän kentän on oltava alle {{length}} merkkiä",
|
||||||
|
"freeze_backup": "Kiinnitä, jotta sitä ei ylikirjoiteta automaattisilla varmuuskopioilla",
|
||||||
|
"unfreeze_backup": "Poista kiinnitys",
|
||||||
|
"backup_frozen": "Varmuuskopio kiinnitetty",
|
||||||
|
"backup_unfrozen": "Varmuuskopion kiinnitys poistettu",
|
||||||
|
"backup_freeze_failed": "Varmuuskopion kiinnitys epäonnistui",
|
||||||
|
"backup_freeze_failed_description": "Sinun on jätettävä vähintään yksi paikka vapaaksi automaattisille varmuuskopioille",
|
||||||
|
"edit_game_modal_button": "Muokkaa pelin tietoja",
|
||||||
|
"game_details": "Pelin tiedot",
|
||||||
|
"currency_symbol": "€",
|
||||||
|
"currency_country": "fi",
|
||||||
|
"prices": "Hinnat",
|
||||||
|
"no_prices_found": "Hintoja ei löytynyt",
|
||||||
|
"view_all_prices": "Napsauta nähdäksesi kaikki hinnat",
|
||||||
|
"retail_price": "Vähittäishinta",
|
||||||
|
"keyshop_price": "Keyshop-hinta",
|
||||||
|
"historical_retail": "Historialliset vähittäishinnat",
|
||||||
|
"historical_keyshop": "Historialliset keyshop-hinnat",
|
||||||
|
"language": "Kieli",
|
||||||
|
"caption": "Tekstitys",
|
||||||
|
"audio": "Ääni",
|
||||||
|
"filter_by_source": "Suodata lähteen mukaan",
|
||||||
|
"no_repacks_found": "Tämän pelin lähteitä ei löytynyt"
|
||||||
|
},
|
||||||
|
"activation": {
|
||||||
|
"title": "Aktivoi Hydra",
|
||||||
|
"installation_id": "Asennustunnus:",
|
||||||
|
"enter_activation_code": "Syötä aktivointikoodisi",
|
||||||
|
"message": "Jos et tiedä mistä sitä pyytää, sinun ei pitäisi sitä olla.",
|
||||||
|
"activate": "Aktivoi",
|
||||||
|
"loading": "Ladataan…"
|
||||||
|
},
|
||||||
|
"downloads": {
|
||||||
|
"resume": "Jatka",
|
||||||
|
"pause": "Keskeytä",
|
||||||
|
"eta": "Lopetus {{eta}}",
|
||||||
|
"paused": "Keskeytetty",
|
||||||
|
"verifying": "Tarkistetaan…",
|
||||||
|
"completed": "Valmis",
|
||||||
|
"removed": "Ei ladattu",
|
||||||
|
"cancel": "Peruuta",
|
||||||
|
"filter": "Hae ladattuja pelejä",
|
||||||
|
"remove": "Poista",
|
||||||
|
"downloading_metadata": "Ladataan metatietoja…",
|
||||||
|
"deleting": "Poistetaan asennustiedostoa…",
|
||||||
|
"delete": "Poista asennustiedosto",
|
||||||
|
"delete_modal_title": "Oletko varma?",
|
||||||
|
"delete_modal_description": "Tämä poistaa kaikki asennustiedostot tietokoneeltasi",
|
||||||
|
"install": "Asenna",
|
||||||
|
"download_in_progress": "Käynnissä",
|
||||||
|
"queued_downloads": "Jonossa olevat lataukset",
|
||||||
|
"downloads_completed": "Valmiit",
|
||||||
|
"queued": "Jonossa",
|
||||||
|
"no_downloads_title": "Täällä on niin tyhjää...",
|
||||||
|
"no_downloads_description": "Et ole vielä ladannut mitään Hydran kautta, mutta ei ole koskaan liian myöhäistä aloittaa.",
|
||||||
|
"checking_files": "Tarkistetaan tiedostoja…",
|
||||||
|
"seeding": "Jakaminen",
|
||||||
|
"stop_seeding": "Lopeta jakaminen",
|
||||||
|
"resume_seeding": "Jatka jakamista",
|
||||||
|
"options": "Hallinnoi",
|
||||||
|
"extract": "Pura tiedostot",
|
||||||
|
"extracting": "Puretaan tiedostoja…"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"downloads_path": "Latausten polku",
|
||||||
|
"change": "Vaihda",
|
||||||
|
"notifications": "Ilmoitukset",
|
||||||
|
"enable_download_notifications": "Latauksen valmistuessa",
|
||||||
|
"enable_repack_list_notifications": "Kun uusi repack lisätään",
|
||||||
|
"real_debrid_api_token_label": "Real-Debrid API-tunnus",
|
||||||
|
"quit_app_instead_hiding": "Sovellus sulkeutuu system tray -alueelle sijasta",
|
||||||
|
"launch_with_system": "Käynnistä Hydra järjestelmän mukana",
|
||||||
|
"general": "Yleiset",
|
||||||
|
"behavior": "Käyttäytyminen",
|
||||||
|
"download_sources": "Latauslähteet",
|
||||||
|
"language": "Kieli",
|
||||||
|
"api_token": "API-avain",
|
||||||
|
"enable_real_debrid": "Ota Real-Debrid käyttöön",
|
||||||
|
"real_debrid_description": "Real-Debrid on rajoittamaton lataaja, jonka avulla voit ladata nopeasti verkossa olevia tiedostoja tai striimata ne välittömästi soittimeen yksityisen verkon kautta, joka kiertää kaikki estot.",
|
||||||
|
"debrid_invalid_token": "Virheellinen API-avain",
|
||||||
|
"debrid_api_token_hint": "API-avain voidaan hankkia <0>täältä</0>",
|
||||||
|
"real_debrid_free_account_error": "Tili \"{{username}}\" - ei ole tilaus. Ota Real-Debrid-tilaus",
|
||||||
|
"debrid_linked_message": "Tili \"{{username}}\" linkitetty",
|
||||||
|
"save_changes": "Tallenna muutokset",
|
||||||
|
"changes_saved": "Muutokset tallennettu onnistuneesti",
|
||||||
|
"download_sources_description": "Hydra hakee latauslinkit näistä lähteistä. URL-osoitteen on sisällettävä suora linkki .json-tiedostoon, joka sisältää latauslinkit.",
|
||||||
|
"validate_download_source": "Vahvista",
|
||||||
|
"remove_download_source": "Poista",
|
||||||
|
"add_download_source": "Lisää lähde",
|
||||||
|
"download_count_zero": "Ei latauksia listassa",
|
||||||
|
"download_count_one": "{{countFormatted}} lataus listassa",
|
||||||
|
"download_count_other": "{{countFormatted}} latausta listassa",
|
||||||
|
"download_source_url": "Lähteen URL-osoite",
|
||||||
|
"add_download_source_description": "Liitä linkki .json-tiedostoon",
|
||||||
|
"download_source_up_to_date": "Ajan tasalla",
|
||||||
|
"download_source_errored": "Virhe",
|
||||||
|
"sync_download_sources": "Päivitä lähteet",
|
||||||
|
"removed_download_source": "Lähde poistettu",
|
||||||
|
"removed_download_sources": "Lähteet poistettu",
|
||||||
|
"cancel_button_confirmation_delete_all_sources": "Ei",
|
||||||
|
"confirm_button_confirmation_delete_all_sources": "Kyllä, poista kaikki",
|
||||||
|
"title_confirmation_delete_all_sources": "Poista kaikki lähteet",
|
||||||
|
"description_confirmation_delete_all_sources": "Poistat kaikki lähteet",
|
||||||
|
"button_delete_all_sources": "Poista kaikki lähteet",
|
||||||
|
"added_download_source": "Lähde lisätty",
|
||||||
|
"download_sources_synced": "Kaikki lähteet päivitetty",
|
||||||
|
"insert_valid_json_url": "Liitä kelvollinen JSON-tiedoston URL-osoite",
|
||||||
|
"found_download_option_zero": "Ei latausvaihtoehtoja löytynyt",
|
||||||
|
"found_download_option_one": "Löytyi {{countFormatted}} latausvaihtoehto",
|
||||||
|
"found_download_option_other": "Löytyi {{countFormatted}} latausvaihtoehtoa",
|
||||||
|
"import": "Tuo",
|
||||||
|
"importing": "Tuodaan...",
|
||||||
|
"public": "Julkinen",
|
||||||
|
"private": "Yksityinen",
|
||||||
|
"friends_only": "Vain kavereille",
|
||||||
|
"privacy": "Yksityisyys",
|
||||||
|
"profile_visibility": "Profiilin näkyvyys",
|
||||||
|
"profile_visibility_description": "Valitse, kuka voi nähdä profiilisi ja kirjastosi",
|
||||||
|
"required_field": "Tämä kenttä on pakollinen",
|
||||||
|
"source_already_exists": "Tämä lähde on jo lisätty",
|
||||||
|
"must_be_valid_url": "Lähteen on oltava kelvollinen URL-osoite",
|
||||||
|
"blocked_users": "Estetyt käyttäjät",
|
||||||
|
"user_unblocked": "Käyttäjä estäminen poistettu",
|
||||||
|
"enable_achievement_notifications": "Kun saavutus avataan",
|
||||||
|
"launch_minimized": "Käynnistä Hydra pienennettynä",
|
||||||
|
"disable_nsfw_alert": "Poista sopimattoman sisällön varoitus käytöstä",
|
||||||
|
"seed_after_download_complete": "Jaa latauksen valmistumisen jälkeen",
|
||||||
|
"show_hidden_achievement_description": "Näytä piilotettujen saavutusten kuvaukset ennen niiden ansaitsemista",
|
||||||
|
"account": "Tili",
|
||||||
|
"no_users_blocked": "Sinulla ei ole estettyjä käyttäjiä",
|
||||||
|
"subscription_active_until": "Hydra Cloud -tilisi on voimassa {{date}} asti",
|
||||||
|
"manage_subscription": "Hallinnoi tilausta",
|
||||||
|
"update_email": "Päivitä sähköposti",
|
||||||
|
"update_password": "Päivitä salasana",
|
||||||
|
"current_email": "Nykyinen sähköposti:",
|
||||||
|
"no_email_account": "Et ole vielä asettanut sähköpostiosoitetta",
|
||||||
|
"account_data_updated_successfully": "Tilitiedot päivitetty onnistuneesti",
|
||||||
|
"renew_subscription": "Uusi Hydra Cloud -tilaus",
|
||||||
|
"subscription_expired_at": "Tilauksesi vanheni {{date}}",
|
||||||
|
"no_subscription": "Nauti Hydrasta täysin rinnoin",
|
||||||
|
"become_subscriber": "Tule Hydra Cloud -tilaajaksi",
|
||||||
|
"subscription_renew_cancelled": "Automaattinen uusinta peruutettu",
|
||||||
|
"subscription_renews_on": "Tilauksesi uusiutuu {{date}}",
|
||||||
|
"bill_sent_until": "Seuraava laskusi lähetetään ennen tätä päivää",
|
||||||
|
"no_themes": "Näyttää siltä, että sinulla ei vielä ole teemoja, mutta älä huoli, napsauta tästä luodaksesi ensimmäisen mestariteoksesi",
|
||||||
|
"editor_tab_code": "Koodi",
|
||||||
|
"editor_tab_info": "Tiedot",
|
||||||
|
"editor_tab_save": "Tallenna",
|
||||||
|
"web_store": "Verkkokauppa",
|
||||||
|
"clear_themes": "Tyhjennä",
|
||||||
|
"create_theme": "Luo",
|
||||||
|
"create_theme_modal_title": "Luo mukautettu teema",
|
||||||
|
"create_theme_modal_description": "Luo uusi teema Hydran ulkoasun mukauttamiseksi",
|
||||||
|
"theme_name": "Nimi",
|
||||||
|
"insert_theme_name": "Syötä teeman nimi",
|
||||||
|
"set_theme": "Aseta teema",
|
||||||
|
"unset_theme": "Poista teema",
|
||||||
|
"delete_theme": "Poista teema",
|
||||||
|
"edit_theme": "Muokkaa teemaa",
|
||||||
|
"delete_all_themes": "Poista kaikki teemat",
|
||||||
|
"delete_all_themes_description": "Tämä poistaa kaikki mukautetut teemasi",
|
||||||
|
"delete_theme_description": "Tämä poistaa teeman {{theme}}",
|
||||||
|
"cancel": "Peruuta",
|
||||||
|
"appearance": "Ulkoasu",
|
||||||
|
"debrid": "Debrid",
|
||||||
|
"debrid_description": "Debrid-palvelut ovat premium-lataajia ilman rajoituksia, joiden avulla voit ladata tiedostoja nopeasti useista tiedostonjakopalveluista, vain internet-yhteytesi nopeuden rajoittamina.",
|
||||||
|
"enable_torbox": "Ota TorBox käyttöön",
|
||||||
|
"torbox_description": "TorBox on premium-palvelusi, joka kilpailee jopa parhaimpien markkinoiden palvelimien kanssa.",
|
||||||
|
"torbox_account_linked": "TorBox-tili linkitetty",
|
||||||
|
"create_real_debrid_account": "Napsauta tästä, jos sinulla ei vielä ole Real-Debrid-tiliä",
|
||||||
|
"create_torbox_account": "Napsauta tästä, jos sinulla ei vielä ole TorBox-tiliä",
|
||||||
|
"real_debrid_account_linked": "Real-Debrid-tili linkitetty",
|
||||||
|
"name_min_length": "Teeman nimen on oltava vähintään 3 merkkiä",
|
||||||
|
"import_theme": "Tuo teema",
|
||||||
|
"import_theme_description": "Tuot teeman {{theme}} teemakaupasta",
|
||||||
|
"error_importing_theme": "Virhe teemaa tuotaessa",
|
||||||
|
"theme_imported": "Teema tuotu onnistuneesti",
|
||||||
|
"enable_friend_request_notifications": "Kun kaveripyyntö vastaanotetaan",
|
||||||
|
"enable_auto_install": "Lataa päivitykset automaattisesti",
|
||||||
|
"common_redist": "Kirjastot",
|
||||||
|
"common_redist_description": "Joidenkin pelien käyttö vaatii kirjastoja. Ongelmien välttämiseksi on suositeltavaa asentaa ne.",
|
||||||
|
"install_common_redist": "Asenna",
|
||||||
|
"installing_common_redist": "Asennetaan…",
|
||||||
|
"show_download_speed_in_megabytes": "Näytä latausnopeus megatavuina sekunnissa",
|
||||||
|
"extract_files_by_default": "Pura tiedostot oletusarvoisesti latauksen jälkeen",
|
||||||
|
"enable_steam_achievements": "Ota Steam-saavutusten haku käyttöön",
|
||||||
|
"achievement_custom_notification_position": "Saavutusilmoitusten sijainti",
|
||||||
|
"top-left": "Vasemmalla ylhäällä",
|
||||||
|
"top-center": "Yläkeskellä",
|
||||||
|
"top-right": "Oikealla ylhäällä",
|
||||||
|
"bottom-left": "Vasemmalla alhaalla",
|
||||||
|
"bottom-center": "Alakeskellä",
|
||||||
|
"bottom-right": "Oikealla alhaalla",
|
||||||
|
"enable_achievement_custom_notifications": "Ota saavutusilmoitukset käyttöön",
|
||||||
|
"alignment": "Tasaus",
|
||||||
|
"variation": "Muunnelma",
|
||||||
|
"default": "Oletus",
|
||||||
|
"rare": "Harvinainen",
|
||||||
|
"platinum": "Platina",
|
||||||
|
"hidden": "Piilotettu",
|
||||||
|
"test_notification": "Testi-ilmoitus",
|
||||||
|
"notification_preview": "Saavutusilmoituksen esikatselu",
|
||||||
|
"enable_friend_start_game_notifications": "Kun kaveri aloittaa pelin pelaamisen"
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"download_complete": "Lataus valmis",
|
||||||
|
"game_ready_to_install": "{{title}} valmis asennettavaksi",
|
||||||
|
"repack_list_updated": "Repack-lista päivitetty",
|
||||||
|
"repack_count_one": "{{count}} repack lisätty",
|
||||||
|
"repack_count_other": "{{count}} repackia lisätty",
|
||||||
|
"new_update_available": "Uusi versio {{version}} saatavilla",
|
||||||
|
"restart_to_install_update": "Käynnistä Hydra uudelleen asentaaksesi päivityksen",
|
||||||
|
"notification_achievement_unlocked_title": "Saavutus avattu pelille {{game}}",
|
||||||
|
"notification_achievement_unlocked_body": "{{achievement}} ja muut {{count}} avattiin",
|
||||||
|
"new_friend_request_description": "{{displayName}} lähetti sinulle kaveripyynnön",
|
||||||
|
"new_friend_request_title": "Uusi kaveripyyntö",
|
||||||
|
"extraction_complete": "Purkaminen valmis",
|
||||||
|
"game_extracted": "{{title}} purettu onnistuneesti",
|
||||||
|
"friend_started_playing_game": "{{displayName}} aloitti pelin pelaamisen",
|
||||||
|
"test_achievement_notification_title": "Tämä on testi-ilmoitus",
|
||||||
|
"test_achievement_notification_description": "Aika siistiä, eikö?"
|
||||||
|
},
|
||||||
|
"system_tray": {
|
||||||
|
"open": "Avaa Hydra",
|
||||||
|
"quit": "Lopeta"
|
||||||
|
},
|
||||||
|
"game_card": {
|
||||||
|
"available_one": "Saatavilla",
|
||||||
|
"available_other": "Saatavilla",
|
||||||
|
"no_downloads": "Ei saatavilla olevia lähteitä",
|
||||||
|
"calculating": "Lasketaan"
|
||||||
|
},
|
||||||
|
"binary_not_found_modal": {
|
||||||
|
"title": "Ohjelmia ei asennettu",
|
||||||
|
"description": "Wine tai Lutris ei löytynyt",
|
||||||
|
"instructions": "Opi oikea tapa asentaa kumpi tahansa Linux-jakelullesi, jotta peli toimii kunnolla"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"close": "Sulje"
|
||||||
|
},
|
||||||
|
"forms": {
|
||||||
|
"toggle_password_visibility": "Näytä salasana"
|
||||||
|
},
|
||||||
|
"user_profile": {
|
||||||
|
"amount_hours": "{{amount}} tuntia",
|
||||||
|
"amount_minutes": "{{amount}} minuuttia",
|
||||||
|
"amount_hours_short": "{{amount}}t",
|
||||||
|
"amount_minutes_short": "{{amount}}min",
|
||||||
|
"last_time_played": "Viimeisin peli {{period}}",
|
||||||
|
"activity": "Viimeisin toiminta",
|
||||||
|
"library": "Kirjasto",
|
||||||
|
"pinned": "Kiinnitetyt",
|
||||||
|
"achievements_earned": "Ansaittu saavutukset",
|
||||||
|
"played_recently": "Äskettäin pelatut",
|
||||||
|
"playtime": "Peliaika",
|
||||||
|
"total_play_time": "Yhteensä pelattu",
|
||||||
|
"manual_playtime_tooltip": "Peliaika on päivitetty manuaalisesti",
|
||||||
|
"no_recent_activity_title": "Hmm... Täällä ei ole mitään",
|
||||||
|
"no_recent_activity_description": "Et ole pelannut mitään vähään aikaan. On aika muuttaa se!",
|
||||||
|
"display_name": "Näyttönimi",
|
||||||
|
"saving": "Tallennetaan",
|
||||||
|
"save": "Tallenna",
|
||||||
|
"edit_profile": "Muokkaa profiilia",
|
||||||
|
"saved_successfully": "Tallennettu onnistuneesti",
|
||||||
|
"try_again": "Yritä uudelleen",
|
||||||
|
"sign_out_modal_title": "Oletko varma?",
|
||||||
|
"cancel": "Peruuta",
|
||||||
|
"successfully_signed_out": "Kirjauduttu ulos onnistuneesti",
|
||||||
|
"sign_out": "Kirjaudu ulos",
|
||||||
|
"playing_for": "Pelattu {{amount}}",
|
||||||
|
"sign_out_modal_text": "Kirjastosi on linkitetty nykyiseen tiliisi. Kirjautumalla ulos kirjastosi ei ole käytettävissä, eikä edistymistä tallenneta. Kirjaudu ulos?",
|
||||||
|
"add_friends": "Lisää kavereita",
|
||||||
|
"add": "Lisää",
|
||||||
|
"friend_code": "Kaverikoodi",
|
||||||
|
"see_profile": "Näytä profiili",
|
||||||
|
"sending": "Lähetetään",
|
||||||
|
"friend_request_sent": "Kaveripyyntö lähetetty",
|
||||||
|
"friends": "Kaverit",
|
||||||
|
"friends_list": "Kaverilista",
|
||||||
|
"user_not_found": "Käyttäjää ei löytynyt",
|
||||||
|
"block_user": "Estä käyttäjä",
|
||||||
|
"add_friend": "Lisää kaveriksi",
|
||||||
|
"request_sent": "Pyyntö lähetetty",
|
||||||
|
"request_received": "Pyyntö vastaanotettu",
|
||||||
|
"accept_request": "Hyväksy pyyntö",
|
||||||
|
"ignore_request": "Ohita pyyntö",
|
||||||
|
"cancel_request": "Peruuta pyyntö",
|
||||||
|
"undo_friendship": "Poista kaveri",
|
||||||
|
"request_accepted": "Pyyntö hyväksytty",
|
||||||
|
"user_blocked_successfully": "Käyttäjä estetty onnistuneesti",
|
||||||
|
"user_block_modal_text": "{{displayName}} estetään",
|
||||||
|
"blocked_users": "Estetyt käyttäjät",
|
||||||
|
"unblock": "Poista esto",
|
||||||
|
"no_friends_added": "Et ole vielä lisännyt yhtään kaveria",
|
||||||
|
"pending": "Odottaa",
|
||||||
|
"no_pending_invites": "Sinulla ei ole vasteita odottavia pyyntöjä",
|
||||||
|
"no_blocked_users": "Et ole estänyt yhtään käyttäjää",
|
||||||
|
"friend_code_copied": "Kaverikoodi kopioitu",
|
||||||
|
"undo_friendship_modal_text": "Tämä purkaa kaverisuhteen käyttäjän {{displayName}} kanssa.",
|
||||||
|
"privacy_hint": "Määrittääksesi kuka voi nähdä tämän, siirry <0>Asetuksiin</0>.",
|
||||||
|
"locked_profile": "Tämä profiili on yksityinen",
|
||||||
|
"image_process_failure": "Kuvan käsittely epäonnistui",
|
||||||
|
"required_field": "Tämä kenttä on pakollinen",
|
||||||
|
"displayname_min_length": "Näyttönimen on oltava vähintään 3 merkkiä.",
|
||||||
|
"displayname_max_length": "Näyttönimen on oltava enintään 50 merkkiä.",
|
||||||
|
"report_profile": "Ilmianna tämä profiili",
|
||||||
|
"report_reason": "Miksi ilmiannat tämän profiilin?",
|
||||||
|
"report_description": "Lisätietoja",
|
||||||
|
"report_description_placeholder": "Lisätietoja",
|
||||||
|
"report": "Ilmianna",
|
||||||
|
"report_reason_hate": "Vihapuhe",
|
||||||
|
"report_reason_sexual_content": "Seksuaalinen sisältö",
|
||||||
|
"report_reason_violence": "Väkivalta",
|
||||||
|
"report_reason_spam": "Roskaposti",
|
||||||
|
"report_reason_other": "Muu",
|
||||||
|
"profile_reported": "Profiili-ilmoitus lähetetty",
|
||||||
|
"your_friend_code": "Kaverikoodisi:",
|
||||||
|
"upload_banner": "Lataa banneri",
|
||||||
|
"uploading_banner": "Ladataan banneria...",
|
||||||
|
"background_image_updated": "Taustakuva päivitetty",
|
||||||
|
"stats": "Tilastot",
|
||||||
|
"achievements": "Saavutukset",
|
||||||
|
"games": "Pelit",
|
||||||
|
"top_percentile": "Top {{percentile}}%",
|
||||||
|
"ranking_updated_weekly": "Sijoitus päivitetään viikoittain",
|
||||||
|
"playing": "Pelaamassa {{game}}",
|
||||||
|
"achievements_unlocked": "Saavutukset avattu",
|
||||||
|
"earned_points": "Ansaitut pisteet:",
|
||||||
|
"show_achievements_on_profile": "Näytä saavutuksesi profiilissasi",
|
||||||
|
"show_points_on_profile": "Näytä ansaitut pisteet profiilissasi",
|
||||||
|
"error_adding_friend": "Kaveripyynnön lähettäminen epäonnistui. Tarkista kaverikoodi",
|
||||||
|
"friend_code_length_error": "Kaverikoodin on oltava 8 merkkiä",
|
||||||
|
"game_removed_from_pinned": "Peli poistettu kiinnitetyistä",
|
||||||
|
"game_added_to_pinned": "Peli lisätty kiinnitettyihin",
|
||||||
|
"karma": "Karma",
|
||||||
|
"karma_count": "karmaa",
|
||||||
|
"karma_description": "Ansittu positiivisilla arvosteluäänillä"
|
||||||
|
},
|
||||||
|
"achievement": {
|
||||||
|
"achievement_unlocked": "Saavutus avattu",
|
||||||
|
"user_achievements": "Käyttäjän {{displayName}} saavutukset",
|
||||||
|
"your_achievements": "Sinun saavutuksesi",
|
||||||
|
"unlocked_at": "Avattu: {{date}}",
|
||||||
|
"subscription_needed": "Hydra Cloud -tilaus tarvitaan tämän sisällön katsomiseen",
|
||||||
|
"new_achievements_unlocked": "{{achievementCount}} uutta saavutusta avattu {{gameCount}} pelistä",
|
||||||
|
"achievement_progress": "{{unlockedCount}}/{{totalCount}} saavutusta",
|
||||||
|
"achievements_unlocked_for_game": "{{achievementCount}} uutta saavutusta avattu pelille {{gameTitle}}",
|
||||||
|
"hidden_achievement_tooltip": "Tämä on piilotettu saavutus",
|
||||||
|
"achievement_earn_points": "Ansaitse {{points}} pistettä tällä saavutuksella",
|
||||||
|
"earned_points": "Ansaitut pisteet:",
|
||||||
|
"available_points": "Saatavilla olevat pisteet:",
|
||||||
|
"how_to_earn_achievements_points": "Kuinka ansaita saavutuspisteitä?"
|
||||||
|
},
|
||||||
|
"hydra_cloud": {
|
||||||
|
"subscription_tour_title": "Hydra Cloud -tilaus",
|
||||||
|
"subscribe_now": "Tilaa nyt",
|
||||||
|
"cloud_saving": "Pilvitallennus",
|
||||||
|
"cloud_achievements": "Tallenna saavutuksesi pilveen",
|
||||||
|
"animated_profile_picture": "Animaoidut profiilikuvat",
|
||||||
|
"premium_support": "Premium-tuki",
|
||||||
|
"show_and_compare_achievements": "Näytä ja vertaile saavutuksiasi muiden käyttäjien saavutuksiin",
|
||||||
|
"animated_profile_banner": "Animoitu profiilin banneri",
|
||||||
|
"hydra_cloud": "Hydra Cloud",
|
||||||
|
"hydra_cloud_feature_found": "Olet juuri löytänyt Hydra Cloud -toiminnon!",
|
||||||
|
"learn_more": "Lue lisää",
|
||||||
|
"debrid_description": "Lataa 4 kertaa nopeammin Nimbuksella"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import nb from "./nb/translation.json";
|
|||||||
import et from "./et/translation.json";
|
import et from "./et/translation.json";
|
||||||
import bg from "./bg/translation.json";
|
import bg from "./bg/translation.json";
|
||||||
import uz from "./uz/translation.json";
|
import uz from "./uz/translation.json";
|
||||||
|
import fi from "./fi/translation.json";
|
||||||
import sv from "./sv/translation.json";
|
import sv from "./sv/translation.json";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -49,6 +50,7 @@ export default {
|
|||||||
da,
|
da,
|
||||||
ar,
|
ar,
|
||||||
fa,
|
fa,
|
||||||
|
fi,
|
||||||
ro,
|
ro,
|
||||||
ca,
|
ca,
|
||||||
bg,
|
bg,
|
||||||
|
|||||||
@@ -345,6 +345,10 @@
|
|||||||
"delete_review_modal_description": "Esta ação não pode ser desfeita.",
|
"delete_review_modal_description": "Esta ação não pode ser desfeita.",
|
||||||
"delete_review_modal_delete_button": "Excluir",
|
"delete_review_modal_delete_button": "Excluir",
|
||||||
"delete_review_modal_cancel_button": "Cancelar",
|
"delete_review_modal_cancel_button": "Cancelar",
|
||||||
|
"show_original": "Mostrar original",
|
||||||
|
"show_translation": "Mostrar tradução",
|
||||||
|
"show_original_translated_from": "Mostrar original (traduzido do {{language}})",
|
||||||
|
"hide_original": "Ocultar original",
|
||||||
"rating_count": "Avaliação"
|
"rating_count": "Avaliação"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
|
|||||||
@@ -259,6 +259,10 @@
|
|||||||
"delete_review_modal_description": "Это действие нельзя отменить.",
|
"delete_review_modal_description": "Это действие нельзя отменить.",
|
||||||
"delete_review_modal_delete_button": "Удалить",
|
"delete_review_modal_delete_button": "Удалить",
|
||||||
"delete_review_modal_cancel_button": "Отмена",
|
"delete_review_modal_cancel_button": "Отмена",
|
||||||
|
"show_original": "Показать оригинал",
|
||||||
|
"show_translation": "Показать перевод",
|
||||||
|
"show_original_translated_from": "Показать оригинал (переведено с {{language}})",
|
||||||
|
"hide_original": "Скрыть оригинал",
|
||||||
"cloud_save": "Облачное сохранение",
|
"cloud_save": "Облачное сохранение",
|
||||||
"cloud_save_description": "Сохраняйте ваш прогресс в облаке и продолжайте играть на любом устройстве",
|
"cloud_save_description": "Сохраняйте ваш прогресс в облаке и продолжайте играть на любом устройстве",
|
||||||
"backups": "Резервные копии",
|
"backups": "Резервные копии",
|
||||||
|
|||||||
@@ -5,15 +5,18 @@ import { logger } from "../logger";
|
|||||||
import { db, gameAchievementsSublevel, levelKeys } from "@main/level";
|
import { db, gameAchievementsSublevel, levelKeys } from "@main/level";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
const LOCAL_CACHE_EXPIRATION = 1000 * 60 * 60; // 1 hour
|
|
||||||
|
|
||||||
const getModifiedSinceHeader = (
|
const getModifiedSinceHeader = (
|
||||||
cachedAchievements: GameAchievement | undefined
|
cachedAchievements: GameAchievement | undefined,
|
||||||
|
userLanguage: string
|
||||||
): Date | undefined => {
|
): Date | undefined => {
|
||||||
if (!cachedAchievements) {
|
if (!cachedAchievements) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (userLanguage != cachedAchievements.language) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return cachedAchievements.updatedAt
|
return cachedAchievements.updatedAt
|
||||||
? new Date(cachedAchievements.updatedAt)
|
? new Date(cachedAchievements.updatedAt)
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -28,13 +31,7 @@ export const getGameAchievementData = async (
|
|||||||
|
|
||||||
const cachedAchievements = await gameAchievementsSublevel.get(gameKey);
|
const cachedAchievements = await gameAchievementsSublevel.get(gameKey);
|
||||||
|
|
||||||
if (cachedAchievements?.achievements && useCachedData)
|
if (cachedAchievements?.achievements && useCachedData) {
|
||||||
return cachedAchievements.achievements;
|
|
||||||
|
|
||||||
if (
|
|
||||||
cachedAchievements?.achievements &&
|
|
||||||
Date.now() < (cachedAchievements.updatedAt ?? 0) + LOCAL_CACHE_EXPIRATION
|
|
||||||
) {
|
|
||||||
return cachedAchievements.achievements;
|
return cachedAchievements.achievements;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,14 +47,15 @@ export const getGameAchievementData = async (
|
|||||||
language,
|
language,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ifModifiedSince: getModifiedSinceHeader(cachedAchievements),
|
ifModifiedSince: getModifiedSinceHeader(cachedAchievements, language),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then(async (achievements) => {
|
.then(async (achievements) => {
|
||||||
await gameAchievementsSublevel.put(gameKey, {
|
await gameAchievementsSublevel.put(gameKey, {
|
||||||
unlockedAchievements: cachedAchievements?.unlockedAchievements ?? [],
|
unlockedAchievements: cachedAchievements?.unlockedAchievements ?? [],
|
||||||
achievements,
|
achievements,
|
||||||
updatedAt: Date.now() + LOCAL_CACHE_EXPIRATION,
|
updatedAt: Date.now(),
|
||||||
|
language,
|
||||||
});
|
});
|
||||||
|
|
||||||
return achievements;
|
return achievements;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const saveAchievementsOnLocal = async (
|
|||||||
achievements: gameAchievement?.achievements ?? [],
|
achievements: gameAchievement?.achievements ?? [],
|
||||||
unlockedAchievements: unlockedAchievements,
|
unlockedAchievements: unlockedAchievements,
|
||||||
updatedAt: gameAchievement?.updatedAt,
|
updatedAt: gameAchievement?.updatedAt,
|
||||||
|
language: gameAchievement?.language,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!sendUpdateEvent) return;
|
if (!sendUpdateEvent) return;
|
||||||
|
|||||||
@@ -66,10 +66,7 @@ export function UserProfileContextProvider({
|
|||||||
const isMe = userDetails?.id === userProfile?.id;
|
const isMe = userDetails?.id === userProfile?.id;
|
||||||
|
|
||||||
const getHeroBackgroundFromImageUrl = async (imageUrl: string) => {
|
const getHeroBackgroundFromImageUrl = async (imageUrl: string) => {
|
||||||
const output = await average(imageUrl, {
|
const output = await average(imageUrl, { amount: 1, format: "hex" });
|
||||||
amount: 1,
|
|
||||||
format: "hex",
|
|
||||||
});
|
|
||||||
|
|
||||||
return `linear-gradient(135deg, ${darkenColor(output as string, 0.5)}, ${darkenColor(output as string, 0.6, 0.5)})`;
|
return `linear-gradient(135deg, ${darkenColor(output as string, 0.5)}, ${darkenColor(output as string, 0.6, 0.5)})`;
|
||||||
};
|
};
|
||||||
@@ -135,28 +132,25 @@ export function UserProfileContextProvider({
|
|||||||
getUserLibraryGames();
|
getUserLibraryGames();
|
||||||
|
|
||||||
return window.electron.hydraApi
|
return window.electron.hydraApi
|
||||||
.get<UserProfile | null>(`/users/${userId}`)
|
.get<UserProfile>(`/users/${userId}`)
|
||||||
.then((userProfile) => {
|
.then((userProfile) => {
|
||||||
if (userProfile) {
|
setUserProfile(userProfile);
|
||||||
setUserProfile(userProfile);
|
|
||||||
|
|
||||||
if (userProfile.profileImageUrl) {
|
if (userProfile.profileImageUrl) {
|
||||||
getHeroBackgroundFromImageUrl(userProfile.profileImageUrl).then(
|
getHeroBackgroundFromImageUrl(userProfile.profileImageUrl).then(
|
||||||
(color) => setHeroBackground(color)
|
(color) => setHeroBackground(color)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showErrorToast(t("user_not_found"));
|
|
||||||
navigate(-1);
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
showErrorToast(t("user_not_found"));
|
||||||
|
navigate(-1);
|
||||||
});
|
});
|
||||||
}, [navigate, getUserStats, getUserLibraryGames, showErrorToast, userId, t]);
|
}, [navigate, getUserStats, getUserLibraryGames, showErrorToast, userId, t]);
|
||||||
|
|
||||||
const getBadges = useCallback(async () => {
|
const getBadges = useCallback(async () => {
|
||||||
const language = i18n.language.split("-")[0];
|
const language = i18n.language.split("-")[0];
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({ locale: language });
|
||||||
locale: language,
|
|
||||||
});
|
|
||||||
|
|
||||||
const badges = await window.electron.hydraApi.get<Badge[]>(
|
const badges = await window.electron.hydraApi.get<Badge[]>(
|
||||||
`/badges?${params.toString()}`,
|
`/badges?${params.toString()}`,
|
||||||
|
|||||||
@@ -153,11 +153,13 @@ export function GameDetailsContent() {
|
|||||||
>
|
>
|
||||||
<section className="game-details__container">
|
<section className="game-details__container">
|
||||||
<div ref={heroRef} className="game-details__hero">
|
<div ref={heroRef} className="game-details__hero">
|
||||||
<img
|
<div className="game-details__hero-image-wrapper">
|
||||||
src={heroImage}
|
<img
|
||||||
className="game-details__hero-image"
|
src={heroImage}
|
||||||
alt={game?.title}
|
className="game-details__hero-image"
|
||||||
/>
|
alt={game?.title}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="game-details__hero-backdrop"
|
className="game-details__hero-backdrop"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -569,27 +569,55 @@ $hero-height: 300px;
|
|||||||
&__hero-logo-backdrop {
|
&__hero-logo-backdrop {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(0deg, rgba(0, 0, 0, 0.3) 60%, transparent 100%);
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
&__hero-image-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 384px;
|
||||||
|
max-height: 384px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 0px 0px 8px 8px;
|
||||||
|
z-index: 0;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgba(0, 0, 0, 0.3) 60%,
|
||||||
|
transparent 100%
|
||||||
|
);
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1250px) {
|
||||||
|
height: calc(350px + 82px);
|
||||||
|
min-height: calc(350px + 84px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__hero-image {
|
&__hero-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc($hero-height + 72px);
|
height: 100%;
|
||||||
min-height: calc($hero-height + 72px);
|
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
object-position: top;
|
object-position: top;
|
||||||
transition: all ease 0.2s;
|
transition: all ease 0.2s;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
border-radius: 0px 0px 8px 8px;
|
||||||
|
|
||||||
@media (min-width: 1250px) {
|
@media (min-width: 1250px) {
|
||||||
object-position: center;
|
object-position: center;
|
||||||
height: calc(350px + 72px);
|
|
||||||
min-height: calc(350px + 72px);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export function GameReviews({
|
|||||||
hasUserReviewed,
|
hasUserReviewed,
|
||||||
onUserReviewedChange,
|
onUserReviewedChange,
|
||||||
}: Readonly<GameReviewsProps>) {
|
}: Readonly<GameReviewsProps>) {
|
||||||
const { t } = useTranslation("game_details");
|
const { t, i18n } = useTranslation("game_details");
|
||||||
const { showSuccessToast, showErrorToast } = useToast();
|
const { showSuccessToast, showErrorToast } = useToast();
|
||||||
|
|
||||||
const [reviews, setReviews] = useState<GameReview[]>([]);
|
const [reviews, setReviews] = useState<GameReview[]>([]);
|
||||||
@@ -129,9 +129,7 @@ export function GameReviews({
|
|||||||
|
|
||||||
const twoHoursInMilliseconds = 2 * 60 * 60 * 1000;
|
const twoHoursInMilliseconds = 2 * 60 * 60 * 1000;
|
||||||
const hasEnoughPlaytime =
|
const hasEnoughPlaytime =
|
||||||
game &&
|
game && game.playTimeInMilliseconds >= twoHoursInMilliseconds;
|
||||||
game.playTimeInMilliseconds >= twoHoursInMilliseconds &&
|
|
||||||
!game.hasManuallyUpdatedPlaytime;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!hasReviewed &&
|
!hasReviewed &&
|
||||||
@@ -146,6 +144,8 @@ export function GameReviews({
|
|||||||
}
|
}
|
||||||
}, [objectId, userDetailsId, shop, game, onUserReviewedChange]);
|
}, [objectId, userDetailsId, shop, game, onUserReviewedChange]);
|
||||||
|
|
||||||
|
console.log("reviews", reviews);
|
||||||
|
|
||||||
const loadReviews = useCallback(
|
const loadReviews = useCallback(
|
||||||
async (reset = false) => {
|
async (reset = false) => {
|
||||||
if (!objectId) return;
|
if (!objectId) return;
|
||||||
@@ -164,6 +164,7 @@ export function GameReviews({
|
|||||||
take: "20",
|
take: "20",
|
||||||
skip: skip.toString(),
|
skip: skip.toString(),
|
||||||
sortBy: reviewsSortBy,
|
sortBy: reviewsSortBy,
|
||||||
|
language: i18n.language,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await window.electron.hydraApi.get(
|
const response = await window.electron.hydraApi.get(
|
||||||
@@ -200,7 +201,7 @@ export function GameReviews({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[objectId, shop, reviewsPage, reviewsSortBy]
|
[objectId, shop, reviewsPage, reviewsSortBy, i18n.language]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleVoteReview = async (
|
const handleVoteReview = async (
|
||||||
@@ -439,6 +440,8 @@ export function GameReviews({
|
|||||||
});
|
});
|
||||||
}, [reviews]);
|
}, [reviews]);
|
||||||
|
|
||||||
|
console.log("reviews", reviews);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="game-details__reviews-section">
|
<div className="game-details__reviews-section">
|
||||||
{showReviewPrompt &&
|
{showReviewPrompt &&
|
||||||
|
|||||||
@@ -18,6 +18,12 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
&__container {
|
||||||
|
padding: 0px 12px 12px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
&--stuck {
|
&--stuck {
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
|||||||
@@ -50,25 +50,29 @@ export function HeroPanel() {
|
|||||||
game?.download?.status === "paused";
|
game?.download?.status === "paused";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="hero-panel">
|
<div className="hero-panel__container">
|
||||||
<div className="hero-panel__content">{getInfo()}</div>
|
<div className="hero-panel">
|
||||||
<div className="hero-panel__actions">
|
<div className="hero-panel__content">{getInfo()}</div>
|
||||||
<HeroPanelActions />
|
<div className="hero-panel__actions">
|
||||||
</div>
|
<HeroPanelActions />
|
||||||
|
</div>
|
||||||
|
|
||||||
{showProgressBar && (
|
{showProgressBar && (
|
||||||
<progress
|
<progress
|
||||||
max={1}
|
max={1}
|
||||||
value={
|
value={
|
||||||
isGameDownloading ? lastPacket?.progress : game?.download?.progress
|
isGameDownloading
|
||||||
}
|
? lastPacket?.progress
|
||||||
className={`hero-panel__progress-bar ${
|
: game?.download?.progress
|
||||||
game?.download?.status === "paused"
|
}
|
||||||
? "hero-panel__progress-bar--disabled"
|
className={`hero-panel__progress-bar ${
|
||||||
: ""
|
game?.download?.status === "paused"
|
||||||
}`}
|
? "hero-panel__progress-bar--disabled"
|
||||||
/>
|
: ""
|
||||||
)}
|
}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/renderer/src/pages/game-details/review-item.scss
Normal file
23
src/renderer/src/pages/game-details/review-item.scss
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
@use "../../scss/globals.scss";
|
||||||
|
|
||||||
|
.game-details {
|
||||||
|
&__review-translation-toggle {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: calc(globals.$spacing-unit * 1);
|
||||||
|
margin-top: calc(globals.$spacing-unit * 1.5);
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import { TrashIcon, ClockIcon } from "@primer/octicons-react";
|
import { TrashIcon, ClockIcon } from "@primer/octicons-react";
|
||||||
import { ThumbsUp, ThumbsDown, Star } from "lucide-react";
|
import { ThumbsUp, ThumbsDown, Star, Languages } from "lucide-react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useState } from "react";
|
||||||
import type { GameReview } from "@types";
|
import type { GameReview } from "@types";
|
||||||
|
|
||||||
import { sanitizeHtml } from "@shared";
|
import { sanitizeHtml } from "@shared";
|
||||||
@@ -10,6 +11,8 @@ import { useDate } from "@renderer/hooks";
|
|||||||
import { formatNumber } from "@renderer/helpers";
|
import { formatNumber } from "@renderer/helpers";
|
||||||
import { Avatar } from "@renderer/components";
|
import { Avatar } from "@renderer/components";
|
||||||
|
|
||||||
|
import "./review-item.scss";
|
||||||
|
|
||||||
interface ReviewItemProps {
|
interface ReviewItemProps {
|
||||||
review: GameReview;
|
review: GameReview;
|
||||||
userDetailsId?: string;
|
userDetailsId?: string;
|
||||||
@@ -63,9 +66,45 @@ export function ReviewItem({
|
|||||||
onAnimationComplete,
|
onAnimationComplete,
|
||||||
}: Readonly<ReviewItemProps>) {
|
}: Readonly<ReviewItemProps>) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { t } = useTranslation("game_details");
|
const { t, i18n } = useTranslation("game_details");
|
||||||
const { formatDistance } = useDate();
|
const { formatDistance } = useDate();
|
||||||
|
|
||||||
|
const [showOriginal, setShowOriginal] = useState(false);
|
||||||
|
|
||||||
|
// Check if this is the user's own review
|
||||||
|
const isOwnReview = userDetailsId === review.user.id;
|
||||||
|
|
||||||
|
// Helper to get base language code (e.g., "pt" from "pt-BR")
|
||||||
|
const getBaseLanguage = (lang: string) => lang.split("-")[0];
|
||||||
|
|
||||||
|
// Check if the review is in a different language (comparing base language codes)
|
||||||
|
const isDifferentLanguage =
|
||||||
|
getBaseLanguage(review.detectedLanguage) !== getBaseLanguage(i18n.language);
|
||||||
|
|
||||||
|
// Check if translation is available and needed (but not for own reviews)
|
||||||
|
const needsTranslation =
|
||||||
|
!isOwnReview &&
|
||||||
|
isDifferentLanguage &&
|
||||||
|
review.translations &&
|
||||||
|
review.translations[i18n.language];
|
||||||
|
|
||||||
|
// Get the full language name using Intl.DisplayNames
|
||||||
|
const getLanguageName = (languageCode: string) => {
|
||||||
|
try {
|
||||||
|
const displayNames = new Intl.DisplayNames([i18n.language], {
|
||||||
|
type: "language",
|
||||||
|
});
|
||||||
|
return displayNames.of(languageCode) || languageCode.toUpperCase();
|
||||||
|
} catch {
|
||||||
|
return languageCode.toUpperCase();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine which content to show - always show original for own reviews
|
||||||
|
const displayContent = needsTranslation
|
||||||
|
? review.translations[i18n.language]
|
||||||
|
: review.reviewHtml;
|
||||||
|
|
||||||
if (isBlocked && !isVisible) {
|
if (isBlocked && !isVisible) {
|
||||||
return (
|
return (
|
||||||
<div className="game-details__review-item">
|
<div className="game-details__review-item">
|
||||||
@@ -135,12 +174,41 @@ export function ReviewItem({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div>
|
||||||
className="game-details__review-content"
|
<div
|
||||||
dangerouslySetInnerHTML={{
|
className="game-details__review-content"
|
||||||
__html: sanitizeHtml(review.reviewHtml),
|
dangerouslySetInnerHTML={{
|
||||||
}}
|
__html: sanitizeHtml(displayContent),
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
{needsTranslation && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="game-details__review-translation-toggle"
|
||||||
|
onClick={() => setShowOriginal(!showOriginal)}
|
||||||
|
>
|
||||||
|
<Languages size={13} />
|
||||||
|
{showOriginal
|
||||||
|
? t("hide_original")
|
||||||
|
: t("show_original_translated_from", {
|
||||||
|
language: getLanguageName(review.detectedLanguage),
|
||||||
|
})}
|
||||||
|
</button>
|
||||||
|
{showOriginal && (
|
||||||
|
<div
|
||||||
|
className="game-details__review-content"
|
||||||
|
style={{
|
||||||
|
opacity: 0.6,
|
||||||
|
marginTop: "12px",
|
||||||
|
}}
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: sanitizeHtml(review.reviewHtml),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="game-details__review-actions">
|
<div className="game-details__review-actions">
|
||||||
<div className="game-details__review-votes">
|
<div className="game-details__review-votes">
|
||||||
<motion.button
|
<motion.button
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ export function sanitizeHtml(html: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove code and pre tags but keep their text content
|
||||||
|
for (const el of tempDiv.querySelectorAll("code, pre")) {
|
||||||
|
const textNode = document.createTextNode(el.textContent || "");
|
||||||
|
el.replaceWith(textNode);
|
||||||
|
}
|
||||||
|
|
||||||
for (const el of tempDiv.querySelectorAll("*")) {
|
for (const el of tempDiv.querySelectorAll("*")) {
|
||||||
for (const attr of Array.from(el.attributes)) {
|
for (const attr of Array.from(el.attributes)) {
|
||||||
const name = attr.name.toLowerCase();
|
const name = attr.name.toLowerCase();
|
||||||
|
|||||||
@@ -260,6 +260,10 @@ export interface GameReview {
|
|||||||
displayName: string;
|
displayName: string;
|
||||||
profileImageUrl: string | null;
|
profileImageUrl: string | null;
|
||||||
};
|
};
|
||||||
|
translations: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
detectedLanguage: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TrendingGame extends ShopAssets {
|
export interface TrendingGame extends ShopAssets {
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ export interface GameAchievement {
|
|||||||
achievements: SteamAchievement[];
|
achievements: SteamAchievement[];
|
||||||
unlockedAchievements: UnlockedAchievement[];
|
unlockedAchievements: UnlockedAchievement[];
|
||||||
updatedAt: number | undefined;
|
updatedAt: number | undefined;
|
||||||
|
language: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AchievementCustomNotificationPosition =
|
export type AchievementCustomNotificationPosition =
|
||||||
|
|||||||
@@ -1047,9 +1047,9 @@
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
global-agent "^3.0.0"
|
global-agent "^3.0.0"
|
||||||
|
|
||||||
"@electron/node-gyp@git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2":
|
"@electron/node-gyp@https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2":
|
||||||
version "10.2.0-electron.1"
|
version "10.2.0-electron.1"
|
||||||
resolved "git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2"
|
resolved "https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2"
|
||||||
dependencies:
|
dependencies:
|
||||||
env-paths "^2.2.0"
|
env-paths "^2.2.0"
|
||||||
exponential-backoff "^3.1.1"
|
exponential-backoff "^3.1.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user