Skip to content

Commit 88329df

Browse files
committed
Add English translation (fix #23)
1 parent f9738ab commit 88329df

12 files changed

Lines changed: 242 additions & 58 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ opt-level = "s"
2424
anyhow = "1.0.97"
2525
chrono = "0.4.40"
2626
home = "0.5.11"
27+
i18n-embed = { version = "0.15.3", features = ["fluent-system", "desktop-requester"] }
28+
i18n-embed-fl = "0.9.3"
2729
iced = { version = "0.13.1", default-features = false, features = [
2830
"tiny-skia",
2931
"image",
3032
"tokio",
3133
"advanced",
3234
] }
35+
lazy_static = "1.5.0"
36+
rust-embed = "8.7.0"
3337
serde = { version = "1.0.219", features = ["derive"] }
3438
tokio = { version = "1.44.1", features = ["full"] }
3539
toml = "0.8.20"

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
</h4>
1414
</div>
1515

16-
> **Warning:** now TimeKeeper only in Russian. I will add new translations (English for example) to version 1.0.0.
16+
> **Note 0:** now TimeKeeper have English and Russian translations.
1717
>
18-
> **Note:** the Windows build of program hasn't been signed yet and I don't think I will ever sign it. I don't have time for this now, so deal with the program signature yourself.
18+
> **Note 1:** the Windows build of program hasn't been signed yet and I don't think I will ever sign it. I don't have time for this now, so deal with the program signature yourself.
1919
2020
## What is TimeKeeper?
2121

i18n.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fallback_language = "en"
2+
3+
[fluent]
4+
assets_dir = "i18n"

i18n/en/time_keeper.ftl

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# TimeKeeper English translation
2+
# (C) 2025 Michail Krasnov <michail383krasnov@mail.ru>
3+
4+
work_notification = Yay! I have to work again!
5+
break_notification = It's time to take a break
6+
7+
#############
8+
# MAIN PAGE #
9+
#############
10+
11+
# Labels
12+
work = Work
13+
break = Break
14+
15+
# Control buttons
16+
start = Start
17+
pause = Pause
18+
stop = Stop
19+
20+
# Statistics subpage
21+
stats_date = Date:
22+
stats_type = Type:
23+
stats_duration = Duration:
24+
empty_stats = Statistics are empty
25+
ten_cycles = The last 10 cycles are shown
26+
27+
# Footer buttons
28+
preferences = Preferences
29+
about = About
30+
show-stats = Show stats
31+
hide-stats = Hide stats
32+
33+
34+
##############
35+
# ABOUT PAGE #
36+
##############
37+
38+
about_version = Version
39+
about_idea = Idea and realization
40+
about_other = Other members
41+
about_internet = TimeKeeper online
42+
about_site = Site
43+
about_repo = Repository
44+
45+
about_id1 = {$name}: design; project text
46+
about_id2 = {$name}: testing; project text
47+
48+
49+
####################
50+
# PREFERENCES PAGE #
51+
####################
52+
53+
pref_header = Preferences
54+
55+
pref_break_alerts = Break alerts
56+
pref_notifications = Notifications
57+
pref_save = Save
58+
pref_close = Close
59+
60+
pref_notifications_tooltip = If the checkbox is selected, TimeKeeper will send notifications to the desktop. If the checkbox is unchecked, a modal window with a countdown to continue work will open on top of all windows instead of notifications
61+
pref_work_slider_tooltip =
62+
The change step is 10 minutes. Press Shift
63+
to change the time in minute increments
64+
pref_work_change = Time changes from 30 minutes to 3 hours
65+
pref_break_slider_tooltip =
66+
Time change by the minute. Press Shift to
67+
set the time in 10-minute increments
68+
pref_break_change = Time changes from 1 to 30 minutes

i18n/ru/time_keeper.ftl

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# TimeKeeper English translation
2+
# (C) 2025 Michail Krasnov <michail383krasnov@mail.ru>
3+
4+
work_notification = Ура! Мне сново надо работать!
5+
break_notification = Пришла пора немного передохнУть. Или передОхнуть.
6+
7+
#############
8+
# MAIN PAGE #
9+
#############
10+
11+
# Labels
12+
work = Работа
13+
break = Перерыв
14+
15+
# Control buttons
16+
start = Старт
17+
pause = Пауза
18+
stop = Стоп
19+
20+
# Statistics subpage
21+
stats_date = Дата:
22+
stats_type = Тип:
23+
stats_duration = Длит.:
24+
empty_stats = Статистика пуста...
25+
ten_cycles = Показываются последние 10 циклов
26+
27+
# Footer buttons
28+
preferences = Настройки
29+
about = О программе
30+
show-stats = Показать статистику
31+
hide-stats = Скрыть статистику
32+
33+
34+
##############
35+
# ABOUT PAGE #
36+
##############
37+
38+
about_version = Версия
39+
about_idea = Идея и реализация
40+
about_other = Другие участники
41+
about_internet = TimeKeeper в интернете
42+
about_site = Сайт
43+
about_repo = Репозиторий
44+
45+
about_id1 = {$name}: дизайн; текст проекта
46+
about_id2 = {$name}: тестирование; текст проекта
47+
48+
49+
####################
50+
# PREFERENCES PAGE #
51+
####################
52+
53+
pref_header = Настройки
54+
55+
pref_break_alerts = Оповещ. о перерыве
56+
pref_notifications = Уведомления
57+
pref_save = Сохранить
58+
pref_close = Закрыть
59+
pref_notifications_tooltip = Если установлен флажок, то TimeKeeper будет отсылать уведомления на рабочий стол. Если флажок не стоит, то вместо уведомлений поверх всех окон будет открываться модальное окно с обратным отсчётом времени до продолжения работы
60+
pref_work_slider_tooltip =
61+
Шаг изменения - 10 минут. Зажмите
62+
Shift, чтобы изменять время поминутно
63+
pref_work_change = Время изменяется от 30 минут до 3 часов
64+
pref_break_slider_tooltip =
65+
Изменение времени поминутно. Зажмите
66+
Shift, чтобы установить шаг в 10 минут
67+
pref_break_change = Время изменяется от 1 до 30 минут

src/i18n.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//! Internationalization support
2+
3+
use i18n_embed::{
4+
DesktopLanguageRequester,
5+
fluent::{FluentLanguageLoader, fluent_language_loader},
6+
};
7+
use lazy_static::lazy_static;
8+
use rust_embed::RustEmbed;
9+
10+
#[derive(RustEmbed)]
11+
#[folder = "./i18n"]
12+
struct Locales;
13+
14+
fn read() -> FluentLanguageLoader {
15+
let ldr: FluentLanguageLoader = fluent_language_loader!();
16+
let req_langs = DesktopLanguageRequester::requested_languages();
17+
i18n_embed::select(&ldr, &Locales, &req_langs).unwrap();
18+
19+
ldr
20+
}
21+
22+
lazy_static! {
23+
pub static ref LANG_LDR: FluentLanguageLoader = read();
24+
}
25+
26+
#[macro_export]
27+
macro_rules! fl {
28+
($message_id:literal) => {{
29+
i18n_embed_fl::fl!($crate::i18n::LANG_LDR, $message_id)
30+
}};
31+
32+
($message_id:literal, $($args:expr),*) => {{
33+
i18n_embed_fl::fl!($crate::i18n::LANG_LDR, $message_id, $($args), *)
34+
}}
35+
}

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
mod conf;
1515
mod consts;
1616
mod external_cmd;
17+
mod i18n;
1718
mod pathes;
1819
mod stats;
1920
mod time;

src/ui/notify.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use winrt_notification::{Duration, Sound, Toast};
1414
#[cfg(unix)]
1515
use notify_rust::Notification;
1616

17-
use crate::consts::PROG_NAME;
17+
use crate::{consts::PROG_NAME, fl};
1818

1919
struct Notify {
2020
title: String,
@@ -66,8 +66,8 @@ impl Notify {
6666

6767
pub fn notify_send(is_work: bool) {
6868
let n_text = match is_work {
69-
false => "Ура! Мне сново надо работать!",
70-
true => "Пришла пора немного передохнУть. Или передОхнуть.",
69+
false => fl!("work_notification"),
70+
true => fl!("break_notification"),
7171
};
7272
let _ = Notify::new(PROG_NAME, n_text).show();
7373
}

src/ui/view/about.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::{
44
consts::{
55
PROG_CRATES_URL, PROG_LOGO, PROG_NAME, PROG_REPO, PROG_SITE, PROG_TELEGRAM, PROG_VER,
66
},
7+
fl,
78
ui::{
89
Message, TimeKeeper,
910
widget::{header, url_button},
@@ -31,28 +32,28 @@ impl TimeKeeper {
3132
pub fn about_page(&self) -> Element<Message> {
3233
let about_devs = column![
3334
column![
34-
row![text("Идея и реализация"), horizontal_rule(0)]
35+
row![text(fl!("about_idea")), horizontal_rule(0)]
3536
.spacing(5)
3637
.align_y(Center),
3738
text("Михаил Краснов <https://github.com/mskrasnov>").size(SMALL_TEXT_SIZE),
3839
]
3940
.spacing(3),
4041
column![
41-
row![text("Другие участники"), horizontal_rule(0)]
42+
row![text(fl!("about_other")), horizontal_rule(0)]
4243
.spacing(5)
4344
.align_y(Center),
44-
text("Данила Макаров: дизайн, текст проекта").size(SMALL_TEXT_SIZE),
45-
text("Максим Марушин: тестирование, текст проекта").size(SMALL_TEXT_SIZE),
45+
text(fl!("about_id1", name = "Данила Макаров")).size(SMALL_TEXT_SIZE),
46+
text(fl!("about_id2", name = "Максим Марушин")).size(SMALL_TEXT_SIZE),
4647
]
4748
.spacing(3),
4849
column![
49-
row![text("TimeKeeper в интернете"), horizontal_rule(0)]
50+
row![text(fl!("about_internet")), horizontal_rule(0)]
5051
.spacing(5)
5152
.align_y(Center),
5253
row![
53-
url_button("Сайт", PROG_SITE).on_press(Message::OpenSiteUrl),
54+
url_button(fl!("about_site"), PROG_SITE).on_press(Message::OpenSiteUrl),
5455
text("|").size(SMALL_TEXT_SIZE),
55-
url_button("Репозиторий", PROG_REPO).on_press(Message::OpenRepoUrl),
56+
url_button(fl!("about_repo"), PROG_REPO).on_press(Message::OpenRepoUrl),
5657
text("|").size(SMALL_TEXT_SIZE),
5758
url_button("crates.io", PROG_CRATES_URL).on_press(Message::OpenCratesUrl),
5859
text("|").size(SMALL_TEXT_SIZE),
@@ -85,7 +86,8 @@ impl TimeKeeper {
8586

8687
fn get_header(&self) -> Column<Message> {
8788
let mut version = String::with_capacity(10);
88-
version.push_str("Версия ");
89+
version.push_str(fl!("about_version").as_str());
90+
version.push(' ');
8991
version.push_str(PROG_VER);
9092

9193
column![header(PROG_NAME).size(20), text(version).size(15),].spacing(5)

0 commit comments

Comments
 (0)