Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion gui/e2e/localization.shot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ test("the Hello table localizes onboarding before App or Settings exists", async
},
onboarding,
]);
await expect(page.getByRole("heading", { name: "選擇音源" })).toBeVisible();
await expect(page.getByRole("heading", { name: "選擇來源" })).toBeVisible();
await expect(page.getByRole("button", { name: "繼續" })).toBeVisible();
await expect(page.locator("html")).toHaveAttribute("lang", "zh-Hant");
await shot(page, "onboarding-zh-Hant");
Expand Down Expand Up @@ -123,6 +123,26 @@ test("a Settings push updates mounted memoized pages and keeps input and raw cho
await shot(page, "discover-zh-Hans");
// A stale Settings message cannot roll the language or the table back.
socket!.send(JSON.stringify(settingsFor("en", 1)));
// The page handles messages in order: once this later shelf shows, the stale
// Settings message before it has been handled too.
const shelves = discover[0];
if (shelves.kind !== "discover" || !shelves.payload.shelves)
throw new Error("discover fixture");
socket!.send(
JSON.stringify({
...shelves,
rev: 2,
payload: {
...shelves.payload,
shelves: [
{ ...shelves.payload.shelves[0], title: "After the stale message" },
...shelves.payload.shelves.slice(1),
],
},
} satisfies ServerMessage),
);
await expect(page.getByText("After the stale message")).toBeVisible();
await expect(page.locator("html")).toHaveAttribute("lang", "zh-Hans");
await expect(
page.getByRole("heading", { name: "发现", exact: true }),
).toBeVisible();
Expand Down
2 changes: 1 addition & 1 deletion gui/src/bindings/InfraStatusStrings.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion gui/src/bindings/SettingsStrings.ts

Large diffs are not rendered by default.

304 changes: 167 additions & 137 deletions gui/src/bindings/strings.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion gui/src/localization.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe("shared browser strings", () => {
onReply={() => {}}
/>,
);
expect(html).toContain("選擇音源");
expect(html).toContain("選擇來源");
expect(html).toContain("繼續");
expect(html).toContain("Spotify");
});
Expand Down
5 changes: 4 additions & 1 deletion src/core/app/soloist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,10 @@ impl App {
Notice::BadKey => self.set_error_status_message(strings.soloist_bad_key, 15),
Notice::Expired => self.set_error_status_message(strings.soloist_expired, 20),
Notice::ExpiresSoon { count, unit } => {
self.set_status_message(strings.soloist_expires_soon(count, &unit), 10);
self.set_status_message(
strings.soloist_expires_soon(count, strings.soloist_expiry_unit(&unit)),
10,
);
}
Notice::DirInUse => self.set_error_status_message(strings.soloist_dir_in_use, 15),
Notice::KeepsExiting => self.set_error_status_message(strings.soloist_keeps_exiting, 15),
Expand Down
2 changes: 1 addition & 1 deletion src/core/i18n/gui/zh_hans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ pub const ZH_HANS: GuiStrings = GuiStrings {
you_hear: "你正在听",
spotify_follow_only: "听众只能跟随 Spotify 歌曲。你再次播放 Spotify 前,他们会继续播放上一首歌。",
stopped_following:
"你已停止跟随房主,正在播放自己的音乐。播放 Spotify 歌曲或等待下一首即可重新跟随。",
"你已停止跟随房主:扬声器正在播放你自己的音乐。播放 Spotify 歌曲或等待下一首即可重新跟随。",
each_own_copy: "每位听众都在自己的设备上播放",
guest_controls: "允许听众控制播放",
host_picks_songs: "歌曲由房主选择。",
Expand Down
4 changes: 2 additions & 2 deletions src/core/i18n/gui/zh_hant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub const ZH_HANT: GuiStrings = GuiStrings {
continue_button: "繼續",
yes: "是",
no: "否",
choose_sources: "選擇音源",
choose_sources: "選擇來源",
choose_sources_hint: "全部不選則只設定 Spotify;之後可以新增或切換來源。",
liked_songs: "喜歡的歌曲",
your_library: "你的音樂庫",
Expand Down Expand Up @@ -225,7 +225,7 @@ pub const ZH_HANT: GuiStrings = GuiStrings {
everyone_hears: "大家正在聽",
you_hear: "你正在聽",
spotify_follow_only: "聽眾只能跟隨 Spotify 歌曲。你再次播放 Spotify 前,他們會繼續播放上一首歌。",
stopped_following: "你已停止跟隨房主,正在播放自己的音樂。播放 Spotify 歌曲或等待下一首即可重新跟隨。",
stopped_following: "你已停止跟隨房主:喇叭正在播放你自己的音樂。播放 Spotify 歌曲或等待下一首即可重新跟隨。",
each_own_copy: "每位聽眾都在自己的裝置上播放",
guest_controls: "允許聽眾控制播放",
host_picks_songs: "歌曲由房主選擇。",
Expand Down
2 changes: 2 additions & 0 deletions src/core/i18n/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ pub const ZH_HANS: HelpStrings = HelpStrings {
not_for_source_template: "{source} 不支持",
only_for_source_template: "仅适用于 {source}",
unavailable_description_template: "{description}({hint})",
settings_button: "按下所选设置项的按钮",
..EN
};
pub const ZH_HANT: HelpStrings = HelpStrings {
Expand Down Expand Up @@ -614,6 +615,7 @@ pub const ZH_HANT: HelpStrings = HelpStrings {
not_for_source_template: "{source} 不支援",
only_for_source_template: "僅適用於 {source}",
unavailable_description_template: "{description}({hint})",
settings_button: "按下所選設定項目的按鈕",
..EN
};

Expand Down
26 changes: 26 additions & 0 deletions src/core/i18n/popups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,19 @@ pub const ZH_HANS: PopupStrings = PopupStrings {
unknown_artist: "未知",
create_results_title: "结果(Enter 添加)",
added_tracks_title_template: "已添加({count})— d=移除,Enter=创建",
soloist_offer_body: "Spotify 拒绝向 librespot 提供这些曲目的音频密钥,部分账号会遇到这种情况。Spotify 自家的播放器 Soloist 可以播放,但需要 Premium。请在设置中:",
soloist_offer_controls: "Enter:打开设置 Esc:暂不",
soloist_offer_not_now: "暂不",
soloist_offer_set_up: "配置 Soloist",
soloist_offer_step_download: "1. Soloist 路径:从 Spotify 下载。",
soloist_offer_step_engine: "3. 播放引擎:Soloist。",
soloist_offer_step_key: "2. Soloist API 密钥:获取密钥,然后填入。",
soloist_offer_title: "通过 Soloist 播放?",
soloist_pair_close: "关闭",
soloist_pair_open: "1. 在同一网络的电脑上打开 Spotify。",
soloist_pair_pick_template: "2. 在它的设备菜单中选择“{name}”。",
soloist_pair_title: "将 spotatui 与 Spotify 配对",
soloist_pair_waiting: "正在等待 Spotify…",
..EN
};

Expand Down Expand Up @@ -533,6 +546,19 @@ pub const ZH_HANT: PopupStrings = PopupStrings {
unknown_artist: "未知",
create_results_title: "結果(Enter 加入)",
added_tracks_title_template: "已加入({count})— d=移除,Enter=建立",
soloist_offer_body: "Spotify 拒絕向 librespot 提供這些曲目的音訊金鑰,部分帳號會遇到這種情況。Spotify 自家的播放器 Soloist 可以播放,但需要 Premium。請在設定中:",
soloist_offer_controls: "Enter:開啟設定 Esc:暫不",
soloist_offer_not_now: "暫不",
soloist_offer_set_up: "設定 Soloist",
soloist_offer_step_download: "1. Soloist 路徑:從 Spotify 下載。",
soloist_offer_step_engine: "3. 播放引擎:Soloist。",
soloist_offer_step_key: "2. Soloist API 金鑰:取得金鑰,然後填入。",
soloist_offer_title: "透過 Soloist 播放?",
soloist_pair_close: "關閉",
soloist_pair_open: "1. 在同一網路的電腦上開啟 Spotify。",
soloist_pair_pick_template: "2. 在它的裝置選單中選擇「{name}」。",
soloist_pair_title: "將 spotatui 與 Spotify 配對",
soloist_pair_waiting: "正在等待 Spotify…",
..EN
};

Expand Down
8 changes: 8 additions & 0 deletions src/core/i18n/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,10 @@ pub struct SettingsStrings {
pub reserved_key_template: &'static str,
pub key_conflict_template: &'static str,
pub option_auto: &'static str,
pub option_soloist_normal: &'static str,
pub option_soloist_high: &'static str,
pub option_soloist_very_high: &'static str,
pub option_soloist_lossless: &'static str,
pub option_auto_color: &'static str,
pub option_en: &'static str,
pub option_zh_hans: &'static str,
Expand Down Expand Up @@ -862,6 +866,10 @@ impl SettingsStrings {
pub fn option_label<'a>(&self, id: &str, raw: &'a str) -> &'a str {
match (id, raw) {
("behavior.language", "auto") => self.option_auto,
("behavior.soloist_audio_quality", "Normal") => self.option_soloist_normal,
("behavior.soloist_audio_quality", "High") => self.option_soloist_high,
("behavior.soloist_audio_quality", "Very high") => self.option_soloist_very_high,
("behavior.soloist_audio_quality", "Lossless") => self.option_soloist_lossless,
("behavior.language", "en") => self.option_en,
("behavior.language", "zh-Hans") => self.option_zh_hans,
("behavior.language", "zh-Hant") => self.option_zh_hant,
Expand Down
4 changes: 4 additions & 0 deletions src/core/i18n/settings/en.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ pub const EN: SettingsStrings = SettingsStrings {
reserved_key_template: "The key {key} is reserved and cannot be remapped",
key_conflict_template: "Key {key} is already assigned to {action}",
option_auto: "Auto (system)",
option_soloist_normal: "Normal",
option_soloist_high: "High",
option_soloist_very_high: "Very high",
option_soloist_lossless: "Lossless",
option_auto_color: "auto",
option_en: "English",
option_zh_hans: "简体中文",
Expand Down
21 changes: 21 additions & 0 deletions src/core/i18n/settings/zh_hans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,5 +362,26 @@ pub const ZH_HANS: SettingsStrings = SettingsStrings {
color_light_magenta: "浅品红(LightMagenta)",
color_light_cyan: "浅青(LightCyan)",
color_white: "白色(White)",
behavior_playback_engine_name: "播放引擎",
behavior_playback_engine_description: "内置播放设备背后用什么播放 Spotify。Soloist 是 Spotify 自家的播放器:用“Soloist 路径”按钮获取,再在“Soloist API 密钥”中填入密钥。",
behavior_soloist_path_name: "Soloist 路径",
behavior_soloist_path_description: "Soloist 引擎运行的 Soloist 程序。“从 Spotify 下载”会获取适用于本系统的官方版本;使用 Soloist 即表示你接受 Spotify 使用条款。",
soloist_download_button: "从 Spotify 下载",
soloist_downloading_button: "正在下载…",
behavior_soloist_api_key_name: "Soloist API 密钥",
behavior_soloist_api_key_description: "Soloist 登录用的密钥,保存在 soloist_credentials.yml。“获取密钥”会打开 Spotify 开发者后台,可在其中创建密钥。SPOTATUI_SOLOIST_API_KEY 优先于此值。本机其他程序可以从 Soloist 的命令行读取该密钥。",
soloist_get_key_button: "获取密钥",
behavior_soloist_audio_quality_name: "Soloist 音质",
behavior_soloist_audio_quality_description: "Soloist 请求的音质(重启后生效)。无损需要 Premium 且所在地区支持无损;如果 Soloist 仍在播放有损音频,请在 Spotify 手机版的设备菜单中选择 spotatui 并设为无损。",
keys_jump_to_start_name: "跳到开头",
keys_jump_to_start_description: "跳到列表第一行",
keys_jump_to_end_name: "跳到末尾",
keys_jump_to_end_description: "跳到列表最后一行",
keys_listening_party_name: "一起听",
keys_listening_party_description: "打开一起听菜单",
option_soloist_normal: "标准",
option_soloist_high: "高",
option_soloist_very_high: "极高",
option_soloist_lossless: "无损",
..EN
};
21 changes: 21 additions & 0 deletions src/core/i18n/settings/zh_hant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,5 +362,26 @@ pub const ZH_HANT: SettingsStrings = SettingsStrings {
color_light_magenta: "淺洋紅(LightMagenta)",
color_light_cyan: "淺青(LightCyan)",
color_white: "白色(White)",
behavior_playback_engine_name: "播放引擎",
behavior_playback_engine_description: "內建串流裝置背後用什麼播放 Spotify。Soloist 是 Spotify 自家的播放器:用「Soloist 路徑」按鈕取得,再在「Soloist API 金鑰」中填入金鑰。",
behavior_soloist_path_name: "Soloist 路徑",
behavior_soloist_path_description: "Soloist 引擎執行的 Soloist 程式。「從 Spotify 下載」會取得適用於本系統的官方版本;使用 Soloist 即表示你接受 Spotify 使用條款。",
soloist_download_button: "從 Spotify 下載",
soloist_downloading_button: "正在下載…",
behavior_soloist_api_key_name: "Soloist API 金鑰",
behavior_soloist_api_key_description: "Soloist 登入用的金鑰,儲存在 soloist_credentials.yml。「取得金鑰」會開啟 Spotify 開發者儀表板,可在其中建立金鑰。SPOTATUI_SOLOIST_API_KEY 優先於此值。本機其他程式可以從 Soloist 的命令列讀取該金鑰。",
soloist_get_key_button: "取得金鑰",
behavior_soloist_audio_quality_name: "Soloist 音質",
behavior_soloist_audio_quality_description: "Soloist 請求的音質(重新啟動後生效)。無損需要 Premium 且所在地區支援無損;如果 Soloist 仍在播放有損音訊,請在 Spotify 手機版的裝置選單中選擇 spotatui 並設為無損。",
keys_jump_to_start_name: "跳到開頭",
keys_jump_to_start_description: "跳到清單第一列",
keys_jump_to_end_name: "跳到結尾",
keys_jump_to_end_description: "跳到清單最後一列",
keys_listening_party_name: "一起聽",
keys_listening_party_description: "開啟一起聽選單",
option_soloist_normal: "標準",
option_soloist_high: "高",
option_soloist_very_high: "極高",
option_soloist_lossless: "無損",
..EN
};
Loading
Loading