From d5ac3a699d70c7169d9659c78ad85ef71a7eb37b Mon Sep 17 00:00:00 2001 From: Matt Sturgeon Date: Mon, 8 Jan 2024 22:17:01 +0000 Subject: [PATCH 1/4] i18n: Add Crowdin config & CI Need to specify `languages_mapping` explicitly, because Crowdin doesn't provide a lowercase locale with underscores, as required by Minecraft. --- .../crowdin-download-translations.yaml | 49 +++++++++++++++++++ .github/workflows/crowdin-upload-sources.yaml | 31 ++++++++++++ .../crowdin-upload-translations.yaml | 33 +++++++++++++ crowdin.yaml | 14 ++++++ 4 files changed, 127 insertions(+) create mode 100644 .github/workflows/crowdin-download-translations.yaml create mode 100644 .github/workflows/crowdin-upload-sources.yaml create mode 100644 .github/workflows/crowdin-upload-translations.yaml create mode 100644 crowdin.yaml diff --git a/.github/workflows/crowdin-download-translations.yaml b/.github/workflows/crowdin-download-translations.yaml new file mode 100644 index 00000000..685eb6bb --- /dev/null +++ b/.github/workflows/crowdin-download-translations.yaml @@ -0,0 +1,49 @@ +name: Crowdin (Download Translations) + +on: + workflow_dispatch: # Allow running manually + schedule: + # https://crontab.guru + - cron: '0 */12 * * *' # Every 12 hours + +# Queue this workflow after others in the 'crowdin' group, to avoid concurrency issues. +concurrency: + group: crowdin + +permissions: + contents: write + pull-requests: write + +jobs: + download_translations: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download to PR + uses: crowdin/github-action@v1 + with: + upload_sources: false + upload_translations: false + download_translations: true + skip_untranslated_strings: true + crowdin_branch_name: ${{ github.ref_name }} + + create_pull_request: true + pull_request_title: Crowdin translations for ${{ github.ref_name }} + pull_request_body: | + New pull request with translations from [Crowdin](https://crowdin.com/project/freecam). + + Powered by [Crowdin's GitHub Action](https://github.com/crowdin/github-action). + pull_request_labels: enhancement, i18n + pull_request_base_branch_name: ${{ github.ref_name }} + localization_branch_name: i18n/${{ github.ref_name }} + commit_message: | + i18n: New translations from Crowdin + + [skip ci] + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/crowdin-upload-sources.yaml b/.github/workflows/crowdin-upload-sources.yaml new file mode 100644 index 00000000..527a3658 --- /dev/null +++ b/.github/workflows/crowdin-upload-sources.yaml @@ -0,0 +1,31 @@ +name: Crowdin (Upload Sources) + +on: + workflow_dispatch: # Allow running manually + push: # Run when en_us is modified on the main branch + branches: + - main + paths: + - '**/lang/en_us.json' + +# Queue this workflow after others in the 'crowdin' group, to avoid concurrency issues. +concurrency: + group: crowdin + +jobs: + upload_sources: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Upload Sources + uses: crowdin/github-action@v1 + with: + upload_sources: true + upload_translations: false + download_translations: false + crowdin_branch_name: ${{ github.ref_name }} + env: + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/crowdin-upload-translations.yaml b/.github/workflows/crowdin-upload-translations.yaml new file mode 100644 index 00000000..30404cd7 --- /dev/null +++ b/.github/workflows/crowdin-upload-translations.yaml @@ -0,0 +1,33 @@ +name: Crowdin (Upload Translations) + +on: + workflow_dispatch: # Allow running manually +## (Disable automatic runs for now) +# push: # Run when a non-en_us lang file is modified on the main branch +# branches: +# - main +# paths: +# - '**/lang/*.json' +# - '!**/lang/en_us.json' + +# Queue this workflow after others in the 'crowdin' group, to avoid concurrency issues. +concurrency: + group: crowdin + +jobs: + upload_translations: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Upload Translations + uses: crowdin/github-action@v1 + with: + upload_sources: false + upload_translations: true + download_translations: false + crowdin_branch_name: ${{ github.ref_name }} + env: + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} \ No newline at end of file diff --git a/crowdin.yaml b/crowdin.yaml new file mode 100644 index 00000000..c5c322d4 --- /dev/null +++ b/crowdin.yaml @@ -0,0 +1,14 @@ +project_id_env: CROWDIN_PROJECT_ID +api_token_env: CROWDIN_PERSONAL_TOKEN +preserve_hierarchy: true + +files: + - source: '/**/lang/en_us.json' + translation: '/**/lang/%locale%.json' + languages_mapping: + locale: + # Valid keys: https://developer.crowdin.com/language-codes + # Valid values ("in-game" locale column): https://minecraft.wiki/w/Language + it: it_it + ja: ja_jp + zh-CN: zh_cn From c95a3d8844824bed95ab7d46766ee66526da2b4c Mon Sep 17 00:00:00 2001 From: Matt Sturgeon Date: Thu, 18 Jan 2024 08:56:00 +0000 Subject: [PATCH 2/4] Add Crowdin badge to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a2c66b20..179f4caf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Freecam +[![Crowdin](https://badges.crowdin.net/freecam/localized.svg)](https://crowdin.com/project/freecam) This mod allows you to control your camera separately from your player. While it is enabled, you can fly around and travel through blocks within your render distance. Disabling it will restore you to your original position. This can be useful for quickly inspecting builds and exploring your world. From 481ced5e26b7710f7b55869befa3be761e18eda9 Mon Sep 17 00:00:00 2001 From: Matt Sturgeon Date: Thu, 18 Jan 2024 08:56:40 +0000 Subject: [PATCH 3/4] Document how to translate --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 179f4caf..ab11eac6 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,13 @@ This mod allows you to control your camera separately from your player. While it This mod works in multiplayer, but may be considered cheating on some servers, so use it at your own risk. +## Translation + +You can help [translate Freecam on Crowdin](https://crowdin.com/project/freecam). +If you're unfamiliar with Crowdin, you can read their [getting started as a volunteer translator guide](https://support.crowdin.com/enterprise/getting-started-for-volunteers). + +If you'd like to translate a language we don't currently target, please [open an issue](https://github.com/MinecraftFreecam/Freecam/issues/new) asking us to enable the language. + ## Keybinds | Name | Description | Default Bind | From ec0b642096424b1b98f6c1a3623890fe3238d006 Mon Sep 17 00:00:00 2001 From: Matt Sturgeon Date: Thu, 18 Jan 2024 09:03:15 +0000 Subject: [PATCH 4/4] =?UTF-8?q?i18n:=20Use=20=C2=A7=20literal=20in=20trans?= =?UTF-8?q?lation=20strings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Crowdin will do this automatically, so do it now to avoid unnecessary PRs. --- .../main/resources/assets/freecam/lang/en_us.json | 12 ++++++------ .../main/resources/assets/freecam/lang/it_it.json | 12 ++++++------ .../main/resources/assets/freecam/lang/ja_jp.json | 12 ++++++------ .../main/resources/assets/freecam/lang/zh_cn.json | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/common/src/main/resources/assets/freecam/lang/en_us.json b/common/src/main/resources/assets/freecam/lang/en_us.json index 2c8460c0..a0c27268 100644 --- a/common/src/main/resources/assets/freecam/lang/en_us.json +++ b/common/src/main/resources/assets/freecam/lang/en_us.json @@ -29,7 +29,7 @@ "text.autoconfig.freecam.option.collision.ignoreAll": "Ignore All Collision", "text.autoconfig.freecam.option.collision.ignoreAll.@Tooltip[0]": "Allows travelling through all blocks in freecam.", "text.autoconfig.freecam.option.collision.ignoreAll.@Tooltip[1]": "§eOverrides above settings.", - "text.autoconfig.freecam.option.collision.ignoreAll.@ModrinthTooltip[2]": "\u00A7cNOTE: Can only be used in singleplayer, creative, or with operator status.", + "text.autoconfig.freecam.option.collision.ignoreAll.@ModrinthTooltip[2]": "§cNOTE: Can only be used in singleplayer, creative, or with operator status.", "text.autoconfig.freecam.option.collision.alwaysCheck": "Always Check Initial Collision", "text.autoconfig.freecam.option.collision.alwaysCheck.@Tooltip[0]": "Whether §7Initial Perspective§r should check for", "text.autoconfig.freecam.option.collision.alwaysCheck.@Tooltip[1]": "collision, even when using §7Ignore All Collision§r.", @@ -55,13 +55,13 @@ "text.autoconfig.freecam.option.utility.disableOnDamage.@Tooltip": "Disables freecam when damage is received.", "text.autoconfig.freecam.option.utility.freezePlayer": "Freeze Player", "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[0]": "Prevents player movement while freecam is active.", - "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[1]": "\u00A7cWARNING: Multiplayer usage not advised.", - "text.autoconfig.freecam.option.utility.freezePlayer.@ModrinthTooltip[1]": "\u00A7cNOTE: Can only be used in singleplayer, creative, or with operator status.", + "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[1]": "§cWARNING: Multiplayer usage not advised.", + "text.autoconfig.freecam.option.utility.freezePlayer.@ModrinthTooltip[1]": "§cNOTE: Can only be used in singleplayer, creative, or with operator status.", "text.autoconfig.freecam.option.utility.allowInteract": "Allow Interaction", "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[0]": "Whether you can interact with blocks/entities in freecam.", - "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[1]": "\u00A7cWARNING: Multiplayer usage not advised.", - "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[1]": "\u00A7cNOTE: Can only be used in singleplayer, creative, or with operator status.", - "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[2]": "\u00A7c*Unless, using interaction mode 'Player'", + "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[1]": "§cWARNING: Multiplayer usage not advised.", + "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[1]": "§cNOTE: Can only be used in singleplayer, creative, or with operator status.", + "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[2]": "§c*Unless, using interaction mode 'Player'", "text.autoconfig.freecam.option.utility.interactionMode": "Interaction Mode", "text.autoconfig.freecam.option.utility.interactionMode.@Tooltip": "The source of block/entity interactions.", "text.autoconfig.freecam.option.utility.interactionMode.camera": "Camera", diff --git a/common/src/main/resources/assets/freecam/lang/it_it.json b/common/src/main/resources/assets/freecam/lang/it_it.json index 87d6e66d..93660451 100644 --- a/common/src/main/resources/assets/freecam/lang/it_it.json +++ b/common/src/main/resources/assets/freecam/lang/it_it.json @@ -29,7 +29,7 @@ "text.autoconfig.freecam.option.collision.ignoreAll": "Ignora Tutte le Collisioni", "text.autoconfig.freecam.option.collision.ignoreAll.@Tooltip[0]": "Consente di viaggiare attraverso tutti i blocchi nella Camera libera.", "text.autoconfig.freecam.option.collision.ignoreAll.@Tooltip[1]": "§eSostituisce le impostazioni precedenti.", - "text.autoconfig.freecam.option.collision.ignoreAll.@ModrinthTooltip[2]": "\u00A7cNOTA: Può essere utilizzato solo in giocatore singolo, creativo o con lo stato di operatore.", + "text.autoconfig.freecam.option.collision.ignoreAll.@ModrinthTooltip[2]": "§cNOTA: Può essere utilizzato solo in giocatore singolo, creativo o con lo stato di operatore.", "text.autoconfig.freecam.option.collision.alwaysCheck": "Controlla Sempre la Collisione Iniziale", "text.autoconfig.freecam.option.collision.alwaysCheck.@Tooltip[0]": "Se la §7Prospettiva Iniziale§r deve controllare la", "text.autoconfig.freecam.option.collision.alwaysCheck.@Tooltip[1]": "collisione, anche quando si utilizza §7Ignora Tutte le Collisioni§r.", @@ -55,13 +55,13 @@ "text.autoconfig.freecam.option.utility.disableOnDamage.@Tooltip": "Disabilità la Camera libera quando viene ricevuto un danno.", "text.autoconfig.freecam.option.utility.freezePlayer": "Blocca Giocatore", "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[0]": "Impedisce il movimento del giocatore mentre la Camera libera è attivatà.", - "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[1]": "\u00A7cATTENZIONE: l'utilizzo del Multigiocatore è sconsigliato.", - "text.autoconfig.freecam.option.utility.freezePlayer.@ModrinthTooltip[1]": "\u00A7cNOTA: Può essere utilizzato solo in giocatore singolo, creativo o con lo stato di operatore.", + "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[1]": "§cATTENZIONE: l'utilizzo del Multigiocatore è sconsigliato.", + "text.autoconfig.freecam.option.utility.freezePlayer.@ModrinthTooltip[1]": "§cNOTA: Può essere utilizzato solo in giocatore singolo, creativo o con lo stato di operatore.", "text.autoconfig.freecam.option.utility.allowInteract": "Consenti Interazione", "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[0]": "Se puoi interagire con blocchi/entità con la Camera libera.", - "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[1]": "\u00A7cATTENZIONE: l'utilizzo del Multigiocatore è sconsigliato.", - "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[1]": "\u00A7cNOTA: Può essere utilizzato solo in giocatore singolo, creativo o con lo stato di operatore.", - "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[2]": "\u00A7c*A meno che, utilizzi la modalità di interazione 'Giocatore'", + "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[1]": "§cATTENZIONE: l'utilizzo del Multigiocatore è sconsigliato.", + "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[1]": "§cNOTA: Può essere utilizzato solo in giocatore singolo, creativo o con lo stato di operatore.", + "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[2]": "§c*A meno che, utilizzi la modalità di interazione 'Giocatore'", "text.autoconfig.freecam.option.utility.interactionMode": "Modalità Interazioni", "text.autoconfig.freecam.option.utility.interactionMode.@Tooltip": "L'origine delle interazioni blocco/entità.", "text.autoconfig.freecam.option.utility.interactionMode.camera": "Camera", diff --git a/common/src/main/resources/assets/freecam/lang/ja_jp.json b/common/src/main/resources/assets/freecam/lang/ja_jp.json index b7e391e6..76e57859 100644 --- a/common/src/main/resources/assets/freecam/lang/ja_jp.json +++ b/common/src/main/resources/assets/freecam/lang/ja_jp.json @@ -29,7 +29,7 @@ "text.autoconfig.freecam.option.collision.ignoreAll": "すべての衝突を無視する", "text.autoconfig.freecam.option.collision.ignoreAll.@Tooltip[0]": "Freecamのすべてのブロックを通過できるようにする。", "text.autoconfig.freecam.option.collision.ignoreAll.@Tooltip[1]": "§e上記の設定を上書きします。", - "text.autoconfig.freecam.option.collision.ignoreAll.@ModrinthTooltip[2]": "\u00A7c注意:シングルプレイヤー、クリエイティブ、オペレーターステータスのみで使用可能できます。", + "text.autoconfig.freecam.option.collision.ignoreAll.@ModrinthTooltip[2]": "§c注意:シングルプレイヤー、クリエイティブ、オペレーターステータスのみで使用可能できます。", "text.autoconfig.freecam.option.collision.alwaysCheck": "初期衝突を常にチェックする", "text.autoconfig.freecam.option.collision.alwaysCheck.@Tooltip[0]": "§7すべての衝突を無視§r を使用している場合でも、", "text.autoconfig.freecam.option.collision.alwaysCheck.@Tooltip[1]": "§7初期視点§r で衝突をチェックするかどうか。", @@ -55,13 +55,13 @@ "text.autoconfig.freecam.option.utility.disableOnDamage.@Tooltip": "ダメージを受けるとFreecamが無効になります。", "text.autoconfig.freecam.option.utility.freezePlayer": "フリーズプレイヤー", "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[0]": "フリーカムがアクティブな間、プレーヤーの移動を防ぎます。", - "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[1]": "\u00A7c警告: マルチプレイヤーでの使用はお勧めしません。", - "text.autoconfig.freecam.option.utility.freezePlayer.@ModrinthTooltip[1]": "\u00A7c注意:シングルプレイヤー、クリエイティブ、オペレーターステータスのみで使用可能できます。", + "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[1]": "§c警告: マルチプレイヤーでの使用はお勧めしません。", + "text.autoconfig.freecam.option.utility.freezePlayer.@ModrinthTooltip[1]": "§c注意:シングルプレイヤー、クリエイティブ、オペレーターステータスのみで使用可能できます。", "text.autoconfig.freecam.option.utility.allowInteract": "インタラクションを許可する", "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[0]": "Freecamでブロック/エンティティを操作できるかどうか。", - "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[1]": "\u00A7c警告: マルチプレイヤーでの使用はお勧めしません。", - "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[1]": "\u00A7c注意:シングルプレイヤー、クリエイティブ、オペレーターステータスのみで使用可能できます。", - "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[2]": "\u00A7c*インタラクションモード'Player'を使用していない場合", + "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[1]": "§c警告: マルチプレイヤーでの使用はお勧めしません。", + "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[1]": "§c注意:シングルプレイヤー、クリエイティブ、オペレーターステータスのみで使用可能できます。", + "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[2]": "§c*インタラクションモード'Player'を使用していない場合", "text.autoconfig.freecam.option.utility.interactionMode": "インタラクションモード", "text.autoconfig.freecam.option.utility.interactionMode.@Tooltip": "ブロック/エンティティ相互作用のソース。", "text.autoconfig.freecam.option.utility.interactionMode.camera": "カメラ", diff --git a/common/src/main/resources/assets/freecam/lang/zh_cn.json b/common/src/main/resources/assets/freecam/lang/zh_cn.json index c3f567a5..69b75896 100644 --- a/common/src/main/resources/assets/freecam/lang/zh_cn.json +++ b/common/src/main/resources/assets/freecam/lang/zh_cn.json @@ -29,7 +29,7 @@ "text.autoconfig.freecam.option.collision.ignoreAll": "忽略所有碰撞", "text.autoconfig.freecam.option.collision.ignoreAll.@Tooltip[0]": "允许在自由视角中穿过所有方块。", "text.autoconfig.freecam.option.collision.ignoreAll.@Tooltip[1]": "§e覆盖以上设置。", - "text.autoconfig.freecam.option.collision.ignoreAll.@ModrinthTooltip[2]": "\u00A7c注意:只能在单人游戏、创造模式或具有管理员身份的情况下使用。", + "text.autoconfig.freecam.option.collision.ignoreAll.@ModrinthTooltip[2]": "§c注意:只能在单人游戏、创造模式或具有管理员身份的情况下使用。", "text.autoconfig.freecam.option.collision.alwaysCheck": "始终检查初始碰撞", "text.autoconfig.freecam.option.collision.alwaysCheck.@Tooltip[0]": "§7初始视角§r是否应该检查", "text.autoconfig.freecam.option.collision.alwaysCheck.@Tooltip[1]": "碰撞,即使使用了§7忽略所有碰撞§r。", @@ -55,13 +55,13 @@ "text.autoconfig.freecam.option.utility.disableOnDamage.@Tooltip": "受到伤害时禁用自由视角。", "text.autoconfig.freecam.option.utility.freezePlayer": "冻结玩家", "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[0]": "启用自由视角时防止玩家移动。", - "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[1]": "\u00A7c警告:不建议多人游戏使用。", - "text.autoconfig.freecam.option.utility.freezePlayer.@ModrinthTooltip[1]": "\u00A7c注意:只能在单人游戏、创造模式或具有管理员身份的情况下使用。", + "text.autoconfig.freecam.option.utility.freezePlayer.@Tooltip[1]": "§c警告:不建议多人游戏使用。", + "text.autoconfig.freecam.option.utility.freezePlayer.@ModrinthTooltip[1]": "§c注意:只能在单人游戏、创造模式或具有管理员身份的情况下使用。", "text.autoconfig.freecam.option.utility.allowInteract": "允许交互", "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[0]": "当你处于自由视角时是否可以与方块/实体交互。", - "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[1]": "\u00A7c警告:不建议多人游戏使用。", - "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[1]": "\u00A7c注意:只能在单人游戏、创造模式或具有管理员身份的情况下使用。", - "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[2]": "\u00A7c*除非你使用的交互模式为‘玩家’", + "text.autoconfig.freecam.option.utility.allowInteract.@Tooltip[1]": "§c警告:不建议多人游戏使用。", + "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[1]": "§c注意:只能在单人游戏、创造模式或具有管理员身份的情况下使用。", + "text.autoconfig.freecam.option.utility.allowInteract.@ModrinthTooltip[2]": "§c*除非你使用的交互模式为‘玩家’", "text.autoconfig.freecam.option.utility.interactionMode": "交互模式", "text.autoconfig.freecam.option.utility.interactionMode.@Tooltip": "方块/实体交互的源头。", "text.autoconfig.freecam.option.utility.interactionMode.camera": "视角",