Skip to content

Commit b5255c8

Browse files
committed
Add Turkish language support (i18n)
- Add embedded translations system for Turkish (tr) and English (en) - Translate editor labels: name, entity, remote, theme, etc. - Translate button tooltips: power, volume, navigation, media controls - Auto-detect user language from Home Assistant settings - Fallback to English when translation not available - Add translations directory with JSON files for future extensibility
1 parent c8f0a76 commit b5255c8

4 files changed

Lines changed: 215 additions & 7 deletions

File tree

translations/en.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"editor": {
3+
"name": "Name (Optional)",
4+
"entity": "Entity",
5+
"remote": "Remote (Optional)",
6+
"theme": "Theme (Optional)",
7+
"roku_tv": "Roku TV?",
8+
"yaml_hint": "Use the YAML editor if you need to specify custom services"
9+
},
10+
"keys": {
11+
"power": "Power",
12+
"volume_up": "Volume Up",
13+
"volume_down": "Volume Down",
14+
"volume_mute": "Mute",
15+
"return": "Return",
16+
"source": "Source",
17+
"info": "Info",
18+
"home": "Home",
19+
"channel_up": "Channel Up",
20+
"channel_down": "Channel Down",
21+
"up": "Up",
22+
"left": "Left",
23+
"enter": "Enter",
24+
"right": "Right",
25+
"down": "Down",
26+
"rewind": "Rewind",
27+
"play": "Play",
28+
"pause": "Pause",
29+
"fast_forward": "Fast Forward"
30+
},
31+
"sources": {
32+
"netflix": "Netflix",
33+
"spotify": "Spotify",
34+
"youtube": "YouTube"
35+
}
36+
}

translations/tr.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"editor": {
3+
"name": "Ad (Opsiyonel)",
4+
"entity": "Varlik",
5+
"remote": "Uzaktan Kumanda (Opsiyonel)",
6+
"theme": "Tema (Opsiyonel)",
7+
"roku_tv": "Roku TV?",
8+
"yaml_hint": "Ozel servisler belirtmek icin YAML editorunu kullanin"
9+
},
10+
"keys": {
11+
"power": "Guc",
12+
"volume_up": "Ses Ac",
13+
"volume_down": "Ses Kis",
14+
"volume_mute": "Sessiz",
15+
"return": "Geri",
16+
"source": "Kaynak",
17+
"info": "Bilgi",
18+
"home": "Ana Sayfa",
19+
"channel_up": "Kanal Yukari",
20+
"channel_down": "Kanal Asagi",
21+
"up": "Yukari",
22+
"left": "Sol",
23+
"enter": "Tamam",
24+
"right": "Sag",
25+
"down": "Asagi",
26+
"rewind": "Geri Sar",
27+
"play": "Oynat",
28+
"pause": "Duraklat",
29+
"fast_forward": "Ileri Sar"
30+
},
31+
"sources": {
32+
"netflix": "Netflix",
33+
"spotify": "Spotify",
34+
"youtube": "YouTube"
35+
}
36+
}

tv-card-editor.js

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,41 @@ const LitElement = Object.getPrototypeOf(
2121
);
2222
const html = LitElement.prototype.html;
2323

24+
// Translations for editor
25+
const editorTranslations = {
26+
"en": {
27+
"name": "Name (Optional)",
28+
"entity": "Entity",
29+
"remote": "Remote (Optional)",
30+
"theme": "Theme (Optional)",
31+
"roku_tv": "Roku TV?",
32+
"yaml_hint": "Use the YAML editor if you need to specify custom services"
33+
},
34+
"tr": {
35+
"name": "Ad (Opsiyonel)",
36+
"entity": "Varlik",
37+
"remote": "Uzaktan Kumanda (Opsiyonel)",
38+
"theme": "Tema (Opsiyonel)",
39+
"roku_tv": "Roku TV?",
40+
"yaml_hint": "Ozel servisler belirtmek icin YAML editorunu kullanin"
41+
}
42+
};
43+
44+
// Helper function to get current language for editor
45+
function getEditorLanguage(hass) {
46+
if (!hass) return "en";
47+
const lang = hass.selectedLanguage || hass.language || "en";
48+
const langCode = lang.substring(0, 2).toLowerCase();
49+
return editorTranslations[langCode] ? langCode : "en";
50+
}
51+
52+
// Helper function to get editor translation
53+
function te(hass, key) {
54+
const lang = getEditorLanguage(hass);
55+
const langData = editorTranslations[lang] || editorTranslations["en"];
56+
return langData[key] || editorTranslations["en"][key] || key;
57+
}
58+
2459
export class TVCardEditor extends LitElement {
2560
setConfig(config) {
2661
this._config = config;
@@ -73,13 +108,13 @@ export class TVCardEditor extends LitElement {
73108
<div class="card-config">
74109
<div class="side-by-side">
75110
<paper-input
76-
label="Name (Optional)"
111+
label="${te(this.hass, "name")}"
77112
.value="${this._name}"
78113
.configValue="${"name"}"
79114
@value-changed="${this._valueChanged}"
80115
></paper-input>
81116
<paper-dropdown-menu
82-
label="Entity"
117+
label="${te(this.hass, "entity")}"
83118
@value-changed="${this._valueChanged}"
84119
.configValue="${"entity"}"
85120
>
@@ -99,7 +134,7 @@ export class TVCardEditor extends LitElement {
99134
</div>
100135
<div class="side-by-side">
101136
<paper-dropdown-menu
102-
label="Remote (Optional)"
137+
label="${te(this.hass, "remote")}"
103138
@value-changed="${this._valueChanged}"
104139
.configValue="${"remote"}"
105140
>
@@ -118,7 +153,7 @@ export class TVCardEditor extends LitElement {
118153
</paper-dropdown-menu>
119154
120155
<paper-dropdown-menu
121-
label="Theme (Optional)"
156+
label="${te(this.hass, "theme")}"
122157
@value-changed="${this._valueChanged}"
123158
.configValue="${"theme"}"
124159
>
@@ -139,10 +174,10 @@ export class TVCardEditor extends LitElement {
139174
?checked="${this._tv !== false}"
140175
.configValue="${"tv"}"
141176
@change="${this._valueChanged}"
142-
>Roku TV?</paper-toggle-button
177+
>${te(this.hass, "roku_tv")}</paper-toggle-button
143178
>
144179
</div>
145-
<div>Use the YAML editor if you need to specify custom services</div>
180+
<div>${te(this.hass, "yaml_hint")}</div>
146181
</div>
147182
`;
148183
}

tv-card.js

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,105 @@ const LitElement = Object.getPrototypeOf(
33
);
44
const html = LitElement.prototype.html;
55

6+
// Translations object - embedded for reliability
7+
const translations = {
8+
"en": {
9+
"editor": {
10+
"name": "Name (Optional)",
11+
"entity": "Entity",
12+
"remote": "Remote (Optional)",
13+
"theme": "Theme (Optional)",
14+
"roku_tv": "Roku TV?",
15+
"yaml_hint": "Use the YAML editor if you need to specify custom services"
16+
},
17+
"keys": {
18+
"power": "Power",
19+
"volume_up": "Volume Up",
20+
"volume_down": "Volume Down",
21+
"volume_mute": "Mute",
22+
"return": "Return",
23+
"source": "Source",
24+
"info": "Info",
25+
"home": "Home",
26+
"channel_up": "Channel Up",
27+
"channel_down": "Channel Down",
28+
"up": "Up",
29+
"left": "Left",
30+
"enter": "Enter",
31+
"right": "Right",
32+
"down": "Down",
33+
"rewind": "Rewind",
34+
"play": "Play",
35+
"pause": "Pause",
36+
"fast_forward": "Fast Forward"
37+
},
38+
"sources": {
39+
"netflix": "Netflix",
40+
"spotify": "Spotify",
41+
"youtube": "YouTube"
42+
}
43+
},
44+
"tr": {
45+
"editor": {
46+
"name": "Ad (Opsiyonel)",
47+
"entity": "Varlik",
48+
"remote": "Uzaktan Kumanda (Opsiyonel)",
49+
"theme": "Tema (Opsiyonel)",
50+
"roku_tv": "Roku TV?",
51+
"yaml_hint": "Ozel servisler belirtmek icin YAML editorunu kullanin"
52+
},
53+
"keys": {
54+
"power": "Guc",
55+
"volume_up": "Ses Ac",
56+
"volume_down": "Ses Kis",
57+
"volume_mute": "Sessiz",
58+
"return": "Geri",
59+
"source": "Kaynak",
60+
"info": "Bilgi",
61+
"home": "Ana Sayfa",
62+
"channel_up": "Kanal Yukari",
63+
"channel_down": "Kanal Asagi",
64+
"up": "Yukari",
65+
"left": "Sol",
66+
"enter": "Tamam",
67+
"right": "Sag",
68+
"down": "Asagi",
69+
"rewind": "Geri Sar",
70+
"play": "Oynat",
71+
"pause": "Duraklat",
72+
"fast_forward": "Ileri Sar"
73+
},
74+
"sources": {
75+
"netflix": "Netflix",
76+
"spotify": "Spotify",
77+
"youtube": "YouTube"
78+
}
79+
}
80+
};
81+
82+
// Helper function to get current language
83+
function getLanguage(hass) {
84+
if (!hass) return "en";
85+
const lang = hass.selectedLanguage || hass.language || "en";
86+
// Return language code (first 2 chars) if full locale provided
87+
const langCode = lang.substring(0, 2).toLowerCase();
88+
return translations[langCode] ? langCode : "en";
89+
}
90+
91+
// Helper function to get translation
92+
function t(hass, category, key) {
93+
const lang = getLanguage(hass);
94+
const langData = translations[lang] || translations["en"];
95+
if (langData[category] && langData[category][key]) {
96+
return langData[category][key];
97+
}
98+
// Fallback to English
99+
if (translations["en"][category] && translations["en"][category][key]) {
100+
return translations["en"][category][key];
101+
}
102+
return key;
103+
}
104+
6105
const keys = {
7106
"power": {"key": "KEY_POWER", "icon": "mdi:power"},
8107
"volume_up": {"key": "KEY_VOLUP", "icon": "mdi:volume-plus"},
@@ -267,12 +366,14 @@ class TVCardServices extends LitElement {
267366
let button_info = this.custom_keys[action] || this.custom_sources[action] || keys[action] || sources[action] || {};
268367
let icon = button_info.icon;
269368
let custom_svg_path = this.custom_icons[icon];
369+
// Get translated title for the button
370+
let buttonTitle = t(this._hass, "keys", action) || t(this._hass, "sources", action) || action;
270371

271372
return html`
272373
<ha-icon-button
273374
.action="${action}"
274375
@click="${this.handleActionClick}"
275-
title="${action}"
376+
title="${buttonTitle}"
276377
.path="${custom_svg_path ? custom_svg_path : ""}"
277378
>
278379
<ha-icon

0 commit comments

Comments
 (0)