Add and remove languages, show * on modified languages, fix string dialog, fix CSV save

This commit is contained in:
Marc Gilleron 2018-11-14 00:47:56 +00:00
parent 95fe113366
commit b09dffce8a
7 changed files with 837 additions and 40 deletions

View File

@ -49,18 +49,21 @@ class _Sorter:
static func save_csv_translation(filepath, data): static func save_csv_translation(filepath, data):
print("Saving: ", data)
var languages = {} var languages = {}
for id in data: for id in data:
var s = data[id] var s = data[id]
for language in s.translations: for language in s.translations:
languages[id] = true languages[language] = true
assert(len(data.languages) > 0) if len(languages) == 0:
printerr("No language found, nothing to save")
return []
languages = languages.keys() languages = languages.keys()
languages.sort() languages.sort()
var first_row = [] var first_row = ["id"]
first_row.resize(len(languages) + 1) first_row.resize(len(languages) + 1)
for i in len(languages): for i in len(languages):
first_row[i + 1] = languages[i] first_row[i + 1] = languages[i]
@ -78,10 +81,10 @@ static func save_csv_translation(filepath, data):
var text = "" var text = ""
if s.translations.has(languages[i]): if s.translations.has(languages[i]):
text = s.translations[languages[i]] text = s.translations[languages[i]]
row[i] = text row[i + 1] = text
rows[row_index] = row rows[row_index] = row
row_index += 1 row_index += 1
print(rows)
var sorter = _Sorter.new() var sorter = _Sorter.new()
rows.sort_custom(sorter, "sort") rows.sort_custom(sorter, "sort")
@ -91,29 +94,26 @@ static func save_csv_translation(filepath, data):
var err = f.open(filepath, File.WRITE) var err = f.open(filepath, File.WRITE)
if err != OK: if err != OK:
printerr("Could not open ", filepath, " for write, code ", err) printerr("Could not open ", filepath, " for write, code ", err)
return false return []
for h in first_row:
f.store_string(str(",", h))
f.store_string("\n")
store_csv_line(f, first_row)
for row in rows: for row in rows:
for i in len(row): store_csv_line(f, row)
var text = row[i]
if i == 0:
f.store_string(text)
else:
f.store_string(",")
# Behavior taken from LibreOffice
if text.contains(delim):
if text.contains('"'):
text = text.replace('"', '""')
text = str('"', text, '"')
f.store_string(text)
f.store_string("\n")
f.close() f.close()
print("Saved ", filepath) print("Saved ", filepath)
return true var saved_languages = languages
return saved_languages
static func store_csv_line(f, a, delim = ","):
for i in len(a):
if i > 0:
f.store_string(",")
var text = str(a[i])
# Behavior taken from LibreOffice
if text.find(delim) != -1 or text.find('"') != -1 or text.find("\n") != -1:
text = str('"', text.replace('"', '""'), '"')
f.store_string(text)
f.store_string("\n")

View File

@ -0,0 +1,68 @@
tool
extends WindowDialog
const Locales = preload("locales.gd")
signal language_selected(language)
onready var _filter_edit = get_node("VBoxContainer/FilterEdit")
onready var _languages_list = get_node("VBoxContainer/LanguagesList")
onready var _ok_button = get_node("VBoxContainer/Buttons/OkButton")
var _hidden_locales = []
func configure(hidden_locales):
_hidden_locales = hidden_locales
refresh_list()
func refresh_list():
_languages_list.clear()
var filter = _filter_edit.text.strip_edges()
var locales = Locales.get_all_locales()
# Hidden root
_languages_list.create_item()
for locale in locales:
if _hidden_locales.find(locale[0]) != -1:
continue
if filter != "" and locale[0].findn(filter) == -1:
continue
var item = _languages_list.create_item()
item.set_text(0, locale[0])
item.set_text(1, locale[1])
_ok_button.disabled = true
func submit():
var item = _languages_list.get_selected()
emit_signal("language_selected", item.get_text(0))
hide()
func _on_OkButton_pressed():
submit()
func _on_CancelButton_pressed():
hide()
func _on_LanguagesList_item_selected():
_ok_button.disabled = false
func _on_LanguagesList_nothing_selected():
_ok_button.disabled = true
func _on_LanguagesList_item_activated():
submit()
func _on_FilterEdit_text_changed(new_text):
refresh_list()

View File

@ -0,0 +1,193 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/zylann.translation_editor/tools/language_selection_dialog.gd" type="Script" id=1]
[node name="LanguageSelectionDialog" type="WindowDialog" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 157.0
margin_top = 145.0
margin_right = 507.0
margin_bottom = 481.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
popup_exclusive = false
window_title = "Select new language"
resizable = true
script = ExtResource( 1 )
[node name="VBoxContainer" type="VBoxContainer" parent="." index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 8.0
margin_top = 8.0
margin_right = -8.0
margin_bottom = -8.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
alignment = 0
_sections_unfolded = [ "Margin" ]
[node name="FilterEdit" type="LineEdit" parent="VBoxContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 334.0
margin_bottom = 24.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 1
size_flags_horizontal = 1
size_flags_vertical = 1
focus_mode = 2
context_menu_enabled = true
placeholder_alpha = 0.6
caret_blink = false
caret_blink_speed = 0.65
caret_position = 0
[node name="LanguagesList" type="Tree" parent="VBoxContainer" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 28.0
margin_right = 334.0
margin_bottom = 284.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = true
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 3
columns = 2
allow_reselect = false
allow_rmb_select = false
hide_folding = false
hide_root = true
drop_mode_flags = 0
select_mode = 1
_sections_unfolded = [ "Size Flags" ]
[node name="Spacer" type="Control" parent="VBoxContainer" index="2"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 288.0
margin_right = 334.0
margin_bottom = 296.0
rect_min_size = Vector2( 0, 8 )
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
_sections_unfolded = [ "Rect" ]
[node name="Buttons" type="HBoxContainer" parent="VBoxContainer" index="3"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 300.0
margin_right = 334.0
margin_bottom = 320.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
custom_constants/separation = 8
alignment = 1
_sections_unfolded = [ "custom_constants" ]
[node name="OkButton" type="Button" parent="VBoxContainer/Buttons" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 63.0
margin_right = 163.0
margin_bottom = 20.0
rect_min_size = Vector2( 100, 0 )
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
toggle_mode = false
enabled_focus_mode = 2
shortcut = null
group = null
text = "OK"
flat = false
align = 1
_sections_unfolded = [ "Rect" ]
[node name="CancelButton" type="Button" parent="VBoxContainer/Buttons" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 171.0
margin_right = 271.0
margin_bottom = 20.0
rect_min_size = Vector2( 100, 0 )
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
toggle_mode = false
enabled_focus_mode = 2
shortcut = null
group = null
text = "Cancel"
flat = false
align = 1
_sections_unfolded = [ "Rect" ]
[connection signal="text_changed" from="VBoxContainer/FilterEdit" to="." method="_on_FilterEdit_text_changed"]
[connection signal="item_activated" from="VBoxContainer/LanguagesList" to="." method="_on_LanguagesList_item_activated"]
[connection signal="item_selected" from="VBoxContainer/LanguagesList" to="." method="_on_LanguagesList_item_selected"]
[connection signal="nothing_selected" from="VBoxContainer/LanguagesList" to="." method="_on_LanguagesList_nothing_selected"]
[connection signal="pressed" from="VBoxContainer/Buttons/OkButton" to="." method="_on_OkButton_pressed"]
[connection signal="pressed" from="VBoxContainer/Buttons/CancelButton" to="." method="_on_CancelButton_pressed"]

View File

@ -0,0 +1,367 @@
# Copied from http://docs.godotengine.org/en/3.0/tutorials/i18n/locales.html
const _locales = [
["aa", "Afar"],
["aa_DJ", "Afar (Djibouti)"],
["aa_ER", "Afar (Eritrea)"],
["aa_ET", "Afar (Ethiopia)"],
["af", "Afrikaans"],
["af_ZA", "Afrikaans (South Africa)"],
["agr_PE", "Aguaruna (Peru)"],
["ak_GH", "Akan (Ghana)"],
["am_ET", "Amharic (Ethiopia)"],
["an_ES", "Aragonese (Spain)"],
["anp_IN", "Angika (India)"],
["ar", "Arabic"],
["ar_AE", "Arabic (United Arab Emirates)"],
["ar_BH", "Arabic (Bahrain)"],
["ar_DZ", "Arabic (Algeria)"],
["ar_EG", "Arabic (Egypt)"],
["ar_IQ", "Arabic (Iraq)"],
["ar_JO", "Arabic (Jordan)"],
["ar_KW", "Arabic (Kuwait)"],
["ar_LB", "Arabic (Lebanon)"],
["ar_LY", "Arabic (Libya)"],
["ar_MA", "Arabic (Morocco)"],
["ar_OM", "Arabic (Oman)"],
["ar_QA", "Arabic (Qatar)"],
["ar_SA", "Arabic (Saudi Arabia)"],
["ar_SD", "Arabic (Sudan)"],
["ar_SY", "Arabic (Syria)"],
["ar_TN", "Arabic (Tunisia)"],
["ar_YE", "Arabic (Yemen)"],
["as_IN", "Assamese (India)"],
["ast_ES", "Asturian (Spain)"],
["ayc_PE", "Southern Aymara (Peru)"],
["ay_PE", "Aymara (Peru)"],
["az_AZ", "Azerbaijani (Azerbaijan)"],
["be", "Belarusian"],
["be_BY", "Belarusian (Belarus)"],
["bem_ZM", "Bemba (Zambia)"],
["ber_DZ", "Berber languages (Algeria)"],
["ber_MA", "Berber languages (Morocco)"],
["bg", "Bulgarian"],
["bg_BG", "Bulgarian (Bulgaria)"],
["bhb_IN", "Bhili (India)"],
["bho_IN", "Bhojpuri (India)"],
["bi_TV", "Bislama (Tuvalu)"],
["bn", "Bengali"],
["bn_BD", "Bengali (Bangladesh)"],
["bn_IN", "Bengali (India)"],
["bo", "Tibetan"],
["bo_CN", "Tibetan (China)"],
["bo_IN", "Tibetan (India)"],
["br_FR", "Breton (France)"],
["brx_IN", "Bodo (India)"],
["bs_BA", "Bosnian (Bosnia and Herzegovina)"],
["byn_ER", "Bilin (Eritrea)"],
["ca", "Catalan"],
["ca_AD", "Catalan (Andorra)"],
["ca_ES", "Catalan (Spain)"],
["ca_FR", "Catalan (France)"],
["ca_IT", "Catalan (Italy)"],
["ce_RU", "Chechen (Russia)"],
["chr_US", "Cherokee (United States)"],
["cmn_TW", "Mandarin Chinese (Taiwan)"],
["crh_UA", "Crimean Tatar (Ukraine)"],
["csb_PL", "Kashubian (Poland)"],
["cs", "Czech"],
["cs_CZ", "Czech (Czech Republic)"],
["cv_RU", "Chuvash (Russia)"],
["cy_GB", "Welsh (United Kingdom)"],
["da", "Danish"],
["da_DK", "Danish (Denmark)"],
["de", "German"],
["de_AT", "German (Austria)"],
["de_BE", "German (Belgium)"],
["de_CH", "German (Switzerland)"],
["de_DE", "German (Germany)"],
["de_IT", "German (Italy)"],
["de_LU", "German (Luxembourg)"],
["doi_IN", "Dogri (India)"],
["dv_MV", "Dhivehi (Maldives)"],
["dz_BT", "Dzongkha (Bhutan)"],
["el", "Greek"],
["el_CY", "Greek (Cyprus)"],
["el_GR", "Greek (Greece)"],
["en", "English"],
["en_AG", "English (Antigua and Barbuda)"],
["en_AU", "English (Australia)"],
["en_BW", "English (Botswana)"],
["en_CA", "English (Canada)"],
["en_DK", "English (Denmark)"],
["en_GB", "English (United Kingdom)"],
["en_HK", "English (Hong Kong)"],
["en_IE", "English (Ireland)"],
["en_IL", "English (Israel)"],
["en_IN", "English (India)"],
["en_NG", "English (Nigeria)"],
["en_MT", "English (Malta)"],
["en_NZ", "English (New Zealand)"],
["en_PH", "English (Philippines)"],
["en_SG", "English (Singapore)"],
["en_US", "English (United States)"],
["en_ZA", "English (South Africa)"],
["en_ZM", "English (Zambia)"],
["en_ZW", "English (Zimbabwe)"],
["eo", "Esperanto"],
["es", "Spanish"],
["es_AR", "Spanish (Argentina)"],
["es_BO", "Spanish (Bolivia)"],
["es_CL", "Spanish (Chile)"],
["es_CO", "Spanish (Colombia)"],
["es_CR", "Spanish (Costa Rica)"],
["en_CU", "Spanish (Cuba)"],
["es_DO", "Spanish (Dominican Republic)"],
["es_EC", "Spanish (Ecuador)"],
["es_ES", "Spanish (Spain)"],
["es_GT", "Spanish (Guatemala)"],
["es_HN", "Spanish (Honduras)"],
["es_MX", "Spanish (Mexico)"],
["es_NI", "Spanish (Nicaragua)"],
["es_PA", "Spanish (Panama)"],
["es_PE", "Spanish (Peru)"],
["es_PR", "Spanish (Puerto Rico)"],
["es_PY", "Spanish (Paraguay)"],
["es_SV", "Spanish (El Salvador)"],
["es_US", "Spanish (United States)"],
["es_UY", "Spanish (Uruguay)"],
["es_VE", "Spanish (Venezuela)"],
["et", "Estonian"],
["et_EE", "Estonian (Estonia)"],
["eu", "Basque"],
["eu_ES", "Basque (Spain)"],
["fa", "Persian"],
["fa_IR", "Persian (Iran)"],
["ff_SN", "Fulah (Senegal)"],
["fi", "Finnish"],
["fi_FI", "Finnish (Finland)"],
["fil_PH", "Filipino (Philippines)"],
["fo_FO", "Faroese (Faroe Islands)"],
["fr", "French"],
["fr_BE", "French (Belgium)"],
["fr_CA", "French (Canada)"],
["fr_CH", "French (Switzerland)"],
["fr_FR", "French (France)"],
["fr_LU", "French (Luxembourg)"],
["fur_IT", "Friulian (Italy)"],
["fy_DE", "Western Frisian (Germany)"],
["fy_NL", "Western Frisian (Netherlands)"],
["ga", "Irish"],
["ga_IE", "Irish (Ireland)"],
["gd_GB", "Scottish Gaelic (United Kingdom)"],
["gez_ER", "Geez (Eritrea)"],
["gez_ET", "Geez (Ethiopia)"],
["gl_ES", "Galician (Spain)"],
["gu_IN", "Gujarati (India)"],
["gv_GB", "Manx (United Kingdom)"],
["hak_TW", "Hakka Chinese (Taiwan)"],
["ha_NG", "Hausa (Nigeria)"],
["he", "Hebrew"],
["he_IL", "Hebrew (Israel)"],
["hi", "Hindi"],
["hi_IN", "Hindi (India)"],
["hne_IN", "Chhattisgarhi (India)"],
["hr", "Croatian"],
["hr_HR", "Croatian (Croatia)"],
["hsb_DE", "Upper Sorbian (Germany)"],
["ht_HT", "Haitian (Haiti)"],
["hu", "Hungarian"],
["hu_HU", "Hungarian (Hungary)"],
["hus_MX", "Huastec (Mexico)"],
["hy_AM", "Armenian (Armenia)"],
["ia_FR", "Interlingua (France)"],
["id", "Indonesian"],
["id_ID", "Indonesian (Indonesia)"],
["ig_NG", "Igbo (Nigeria)"],
["ik_CA", "Inupiaq (Canada)"],
["is", "Icelandic"],
["is_IS", "Icelandic (Iceland)"],
["it", "Italian"],
["it_CH", "Italian (Switzerland)"],
["it_IT", "Italian (Italy)"],
["iu_CA", "Inuktitut (Canada)"],
["ja", "Japanese"],
["ja_JP", "Japanese (Japan)"],
["kab_DZ", "Kabyle (Algeria)"],
["ka_GE", "Georgian (Georgia)"],
["kk_KZ", "Kazakh (Kazakhstan)"],
["kl_GL", "Kalaallisut (Greenland)"],
["km_KH", "Central Khmer (Cambodia)"],
["kn_IN", "Kannada (India)"],
["kok_IN", "Konkani (India)"],
["ko", "Korean"],
["ko_KR", "Korean (South Korea)"],
["ks_IN", "Kashmiri (India)"],
["ku", "Kurdish"],
["ku_TR", "Kurdish (Turkey)"],
["kw_GB", "Cornish (United Kingdom)"],
["ky_KG", "Kirghiz (Kyrgyzstan)"],
["lb_LU", "Luxembourgish (Luxembourg)"],
["lg_UG", "Ganda (Uganda)"],
["li_BE", "Limburgan (Belgium)"],
["li_NL", "Limburgan (Netherlands)"],
["lij_IT", "Ligurian (Italy)"],
["ln_CD", "Lingala (Congo)"],
["lo_LA", "Lao (Laos)"],
["lt", "Lithuanian"],
["lt_LT", "Lithuanian (Lithuania)"],
["lv", "Latvian"],
["lv_LV", "Latvian (Latvia)"],
["lzh_TW", "Literary Chinese (Taiwan)"],
["mag_IN", "Magahi (India)"],
["mai_IN", "Maithili (India)"],
["mg_MG", "Malagasy (Madagascar)"],
["mh_MH", "Marshallese (Marshall Islands)"],
["mhr_RU", "Eastern Mari (Russia)"],
["mi_NZ", "Maori (New Zealand)"],
["miq_NI", "Mískito (Nicaragua)"],
["mk", "Macedonian"],
["mk_MK", "Macedonian (Macedonia)"],
["ml_IN", "Malayalam (India)"],
["mni_IN", "Manipuri (India)"],
["mn_MN", "Mongolian (Mongolia)"],
["mr_IN", "Marathi (India)"],
["ms", "Malay"],
["ms_MY", "Malay (Malaysia)"],
["mt", "Maltese"],
["mt_MT", "Maltese (Malta)"],
["my_MM", "Burmese (Myanmar)"],
["myv_RU", "Erzya (Russia)"],
["nah_MX", "Nahuatl languages (Mexico)"],
["nan_TW", "Min Nan Chinese (Taiwan)"],
["nb", "Norwegian Bokmål"],
["nb_NO", "Norwegian Bokmål (Norway)"],
["nds_DE", "Low German (Germany)"],
["nds_NL", "Low German (Netherlands)"],
["ne_NP", "Nepali (Nepal)"],
["nhn_MX", "Central Nahuatl (Mexico)"],
["niu_NU", "Niuean (Niue)"],
["niu_NZ", "Niuean (New Zealand)"],
["nl", "Dutch"],
["nl_AW", "Dutch (Aruba)"],
["nl_BE", "Dutch (Belgium)"],
["nl_NL", "Dutch (Netherlands)"],
["nn", "Norwegian Nynorsk"],
["nn_NO", "Norwegian Nynorsk (Norway)"],
["no", "Norwegian"],
["no_NO", "Norwegian (Norway)"],
["nr_ZA", "South Ndebele (South Africa)"],
["nso_ZA", "Pedi (South Africa)"],
["oc_FR", "Occitan (France)"],
["om", "Oromo"],
["om_ET", "Oromo (Ethiopia)"],
["om_KE", "Oromo (Kenya)"],
["or_IN", "Oriya (India)"],
["os_RU", "Ossetian (Russia)"],
["pa_IN", "Panjabi (India)"],
["pap", "Papiamento"],
["pap_AN", "Papiamento (Netherlands Antilles)"],
["pap_AW", "Papiamento (Aruba)"],
["pap_CW", "Papiamento (Curaçao)"],
["pa_PK", "Panjabi (Pakistan)"],
["pl", "Polish"],
["pl_PL", "Polish (Poland)"],
["pr", "Pirate"],
["ps_AF", "Pushto (Afghanistan)"],
["pt", "Portuguese"],
["pt_BR", "Portuguese (Brazil)"],
["pt_PT", "Portuguese (Portugal)"],
["quy_PE", "Ayacucho Quechua (Peru)"],
["quz_PE", "Cusco Quechua (Peru)"],
["raj_IN", "Rajasthani (India)"],
["ro", "Romanian"],
["ro_RO", "Romanian (Romania)"],
["ru", "Russian"],
["ru_RU", "Russian (Russia)"],
["ru_UA", "Russian (Ukraine)"],
["rw_RW", "Kinyarwanda (Rwanda)"],
["sa_IN", "Sanskrit (India)"],
["sat_IN", "Santali (India)"],
["sc_IT", "Sardinian (Italy)"],
["sco", "Scots"],
["sd_IN", "Sindhi (India)"],
["se_NO", "Northern Sami (Norway)"],
["sgs_LT", "Samogitian (Lithuania)"],
["shs_CA", "Shuswap (Canada)"],
["sid_ET", "Sidamo (Ethiopia)"],
["si_LK", "Sinhala (Sri Lanka)"],
["sk", "Slovak"],
["sk_SK", "Slovak (Slovakia)"],
["sl", "Slovenian"],
["so", "Somali"],
["so_DJ", "Somali (Djibouti)"],
["so_ET", "Somali (Ethiopia)"],
["so_KE", "Somali (Kenya)"],
["so_SO", "Somali (Somalia)"],
["son_ML", "Songhai languages (Mali)"],
["sq", "Albanian"],
["sq_AL", "Albanian (Albania)"],
["sq_KV", "Albanian (Kosovo)"],
["sq_MK", "Albanian (Macedonia)"],
["sr", "Serbian"],
["sr_BA", "Serbian (Bosnia and Herzegovina)"],
["sr_CS", "Serbian (Serbia and Montenegro)"],
["sr_ME", "Serbian (Montenegro)"],
["sr_RS", "Serbian (Serbia)"],
["ss_ZA", "Swati (South Africa)"],
["st_ZA", "Southern Sotho (South Africa)"],
["sv", "Swedish"],
["sv_FI", "Swedish (Finland)"],
["sv_SE", "Swedish (Sweden)"],
["sw_KE", "Swahili (Kenya)"],
["sw_TZ", "Swahili (Tanzania)"],
["szl_PL", "Silesian (Poland)"],
["ta", "Tamil"],
["ta_IN", "Tamil (India)"],
["ta_LK", "Tamil (Sri Lanka)"],
["tcy_IN", "Tulu (India)"],
["te_IN", "Telugu (India)"],
["tg_TJ", "Tajik (Tajikistan)"],
["the_NP", "Chitwania Tharu (Nepal)"],
["th", "Thai"],
["th_TH", "Thai (Thailand)"],
["th_TH_TH", "Thai (Thailand,TH)"],
["ti", "Tigrinya"],
["ti_ER", "Tigrinya (Eritrea)"],
["ti_ET", "Tigrinya (Ethiopia)"],
["tig_ER", "Tigre (Eritrea)"],
["tk_TM", "Turkmen (Turkmenistan)"],
["tl_PH", "Tagalog (Philippines)"],
["tn_ZA", "Tswana (South Africa)"],
["tr", "Turkish"],
["tr_CY", "Turkish (Cyprus)"],
["tr_TR", "Turkish (Turkey)"],
["ts_ZA", "Tsonga (South Africa)"],
["tt_RU", "Tatar (Russia)"],
["ug_CN", "Uighur (China)"],
["uk", "Ukrainian"],
["uk_UA", "Ukrainian (Ukraine)"],
["unm_US", "Unami (United States)"],
["ur", "Urdu"],
["ur_IN", "Urdu (India)"],
["ur_PK", "Urdu (Pakistan)"],
["uz", "Uzbek"],
["uz_UZ", "Uzbek (Uzbekistan)"],
["ve_ZA", "Venda (South Africa)"],
["vi", "Vietnamese"],
["vi_VN", "Vietnamese (Vietnam)"],
["wa_BE", "Walloon (Belgium)"],
["wae_CH", "Walser (Switzerland)"],
["wal_ET", "Wolaytta (Ethiopia)"],
["wo_SN", "Wolof (Senegal)"],
["xh_ZA", "Xhosa (South Africa)"],
["yi_US", "Yiddish (United States)"],
["yo_NG", "Yoruba (Nigeria)"],
["yue_HK", "Yue Chinese (Hong Kong)"],
["zh", "Chinese"],
["zh_CN", "Chinese (China)"],
["zh_HK", "Chinese (Hong Kong)"],
["zh_SG", "Chinese (Singapore)"],
["zh_TW", "Chinese (Taiwan)"],
["zu_ZA", "Zulu (South Africa)"]
]
static func get_all_locales():
return _locales

View File

@ -81,6 +81,7 @@ class _Sorter:
static func save_po_translations(folder_path, translations, languages_to_save): static func save_po_translations(folder_path, translations, languages_to_save):
var sorter = _Sorter.new() var sorter = _Sorter.new()
var saved_languages = []
for language in languages_to_save: for language in languages_to_save:
@ -115,6 +116,9 @@ static func save_po_translations(folder_path, translations, languages_to_save):
f.store_line("") f.store_line("")
f.close() f.close()
saved_languages.append(language)
return saved_languages
static func _write_msg(f, msgtype, msg): static func _write_msg(f, msgtype, msg):

View File

@ -4,10 +4,13 @@ extends Panel
const CsvLoader = preload("csv_loader.gd") const CsvLoader = preload("csv_loader.gd")
const PoLoader = preload("po_loader.gd") const PoLoader = preload("po_loader.gd")
const StringEditionDialog = preload("string_edition_dialog.tscn") const StringEditionDialog = preload("string_edition_dialog.tscn")
const LanguageSelectionDialog = preload("language_selection_dialog.tscn")
const MENU_FILE_OPEN = 0 const MENU_FILE_OPEN = 0
const MENU_FILE_SAVE = 1 const MENU_FILE_SAVE = 1
const MENU_FILE_SAVE_AS = 2 const MENU_FILE_SAVE_AS = 2
const MENU_FILE_ADD_LANGUAGE = 3
const MENU_FILE_REMOVE_LANGUAGE = 4
onready var _file_menu = get_node("VBoxContainer/MenuBar/FileMenu") onready var _file_menu = get_node("VBoxContainer/MenuBar/FileMenu")
onready var _edit_menu = get_node("VBoxContainer/MenuBar/EditMenu") onready var _edit_menu = get_node("VBoxContainer/MenuBar/EditMenu")
@ -17,19 +20,19 @@ onready var _translation_tab_container = \
onready var _notes_edit = get_node("VBoxContainer/Main/RightPane/VSplitContainer/VBoxContainer/NotesEdit") onready var _notes_edit = get_node("VBoxContainer/Main/RightPane/VSplitContainer/VBoxContainer/NotesEdit")
var _string_edit_dialog = null var _string_edit_dialog = null
var _language_selection_dialog = null
var _remove_language_confirmation_dialog = null
var _open_dialog = null var _open_dialog = null
var _save_dialog = null var _save_dialog = null
# This is set when integrated as a Godot plugin # This is set when integrated as a Godot plugin
var _base_control = null var _base_control = null
var _data = null
# TODO Make this a config of some sort
var _languages = ["en", "fr"]
var _current_file = null
var _translation_edits = {} var _translation_edits = {}
var _data = {}
var _languages = []
var _current_file = null
var _modified_languages = {}
func _ready(): func _ready():
# I don't want any of this to run in the edited scene (because `tool`)... # I don't want any of this to run in the edited scene (because `tool`)...
@ -39,6 +42,10 @@ func _ready():
_file_menu.get_popup().add_item("Open...", MENU_FILE_OPEN) _file_menu.get_popup().add_item("Open...", MENU_FILE_OPEN)
_file_menu.get_popup().add_item("Save", MENU_FILE_SAVE) _file_menu.get_popup().add_item("Save", MENU_FILE_SAVE)
_file_menu.get_popup().add_item("Save as...", MENU_FILE_SAVE_AS) _file_menu.get_popup().add_item("Save as...", MENU_FILE_SAVE_AS)
_file_menu.get_popup().add_separator()
_file_menu.get_popup().add_item("Add language...", MENU_FILE_ADD_LANGUAGE)
_file_menu.get_popup().add_item("Remove language", MENU_FILE_REMOVE_LANGUAGE)
_file_menu.get_popup().set_item_disabled(_file_menu.get_popup().get_item_index(MENU_FILE_REMOVE_LANGUAGE), true)
_file_menu.get_popup().connect("id_pressed", self, "_on_FileMenu_id_pressed") _file_menu.get_popup().connect("id_pressed", self, "_on_FileMenu_id_pressed")
_edit_menu.get_popup().connect("id_pressed", self, "_on_EditMenu_id_pressed") _edit_menu.get_popup().connect("id_pressed", self, "_on_EditMenu_id_pressed")
@ -66,7 +73,17 @@ func _ready():
_string_edit_dialog = StringEditionDialog.instance() _string_edit_dialog = StringEditionDialog.instance()
_string_edit_dialog.set_validator(funcref(self, "_validate_new_string_id")) _string_edit_dialog.set_validator(funcref(self, "_validate_new_string_id"))
_string_edit_dialog.connect("submitted", self, "_on_StringEditionDialog_submitted")
dialogs_parent.add_child(_string_edit_dialog) dialogs_parent.add_child(_string_edit_dialog)
_language_selection_dialog = LanguageSelectionDialog.instance()
_language_selection_dialog.connect("language_selected", self, "_on_LanguageSelectionDialog_language_selected")
dialogs_parent.add_child(_language_selection_dialog)
_remove_language_confirmation_dialog = ConfirmationDialog.new()
_remove_language_confirmation_dialog.dialog_text = "Do you really want to remove this language? (There is no undo!)"
_remove_language_confirmation_dialog.connect("confirmed", self, "_on_RemoveLanguageConfirmationDialog_confirmed")
dialogs_parent.add_child(_remove_language_confirmation_dialog)
func configure_for_godot_integration(base_control): func configure_for_godot_integration(base_control):
@ -79,10 +96,21 @@ func _on_FileMenu_id_pressed(id):
match id: match id:
MENU_FILE_OPEN: MENU_FILE_OPEN:
_open_dialog.popup_centered_ratio() _open_dialog.popup_centered_ratio()
MENU_FILE_SAVE: MENU_FILE_SAVE:
_save() _save()
MENU_FILE_SAVE_AS: MENU_FILE_SAVE_AS:
_save_dialog.popup_centered_ratio() _save_dialog.popup_centered_ratio()
MENU_FILE_ADD_LANGUAGE:
_language_selection_dialog.configure(_languages)
_language_selection_dialog.popup_centered_ratio()
MENU_FILE_REMOVE_LANGUAGE:
var language = get_current_language()
_remove_language_confirmation_dialog.window_title = str("Remove language `", language, "`")
_remove_language_confirmation_dialog.popup_centered_minsize()
func _on_EditMenu_id_pressed(id): func _on_EditMenu_id_pressed(id):
@ -101,6 +129,10 @@ func _on_SaveButton_pressed():
_save() _save()
func _on_LanguageSelectionDialog_language_selected(language):
_add_language(language)
func _save(): func _save():
if _current_file == null: if _current_file == null:
_save_dialog.popup_centered_ratio() _save_dialog.popup_centered_ratio()
@ -118,6 +150,13 @@ func load_file(filepath):
printerr("Unknown file format, cannot load ", filepath) printerr("Unknown file format, cannot load ", filepath)
return return
_languages.clear()
for strid in _data:
var s = _data[strid]
for language in s.translations:
if _languages.find(language) == -1:
_languages.append(language)
_translation_edits.clear() _translation_edits.clear()
for i in _translation_tab_container.get_child_count(): for i in _translation_tab_container.get_child_count():
@ -126,25 +165,108 @@ func load_file(filepath):
child.queue_free() child.queue_free()
for language in _languages: for language in _languages:
var edit = TextEdit.new() _create_translation_edit(language)
var tab_index = _translation_tab_container.get_tab_count()
_translation_tab_container.add_child(edit)
_translation_tab_container.set_tab_title(tab_index, language)
_translation_edits[language] = edit
refresh_list() refresh_list()
_current_file = filepath _current_file = filepath
_modified_languages.clear()
func _create_translation_edit(language):
assert(not _translation_edits.has(language)) # boom
var edit = TextEdit.new()
edit.hide()
var tab_index = _translation_tab_container.get_tab_count()
_translation_tab_container.add_child(edit)
_translation_tab_container.set_tab_title(tab_index, language)
_translation_edits[language] = edit
edit.connect("text_changed", self, "_on_TranslationEdit_text_changed", [language])
func _on_TranslationEdit_text_changed(language):
var edit = _translation_edits[language]
var selected_strids = _string_list.get_selected_items()
# TODO Don't show the editor if no strings are selected
if len(selected_strids) != 1:
return
#assert(len(selected_strids) == 1)
var strid = _string_list.get_item_text(selected_strids[0])
var prev_text = null
var s = _data[strid]
if s.translations.has(language):
prev_text = s.translations[language]
if prev_text != edit.text:
s.translations[language] = edit.text
_set_language_modified(language)
func _on_NotesEdit_text_changed():
var selected_strids = _string_list.get_selected_items()
# TODO Don't show the editor if no strings are selected
if len(selected_strids) != 1:
return
#assert(len(selected_strids) == 1)
var strid = _string_list.get_item_text(selected_strids[0])
var s = _data[strid]
if s.comments != _notes_edit.text:
s.comments = _notes_edit.text
for language in _languages:
_set_language_modified(language)
func _set_language_modified(language):
if _modified_languages.has(language):
return
_modified_languages[language] = true
_set_language_tab_title(language, str(language, "*"))
func _set_language_unmodified(language):
if not _modified_languages.has(language):
return
_modified_languages.erase(language)
_set_language_tab_title(language, language)
func _set_language_tab_title(language, title):
var page = _translation_edits[language]
for i in _translation_tab_container.get_child_count():
if _translation_tab_container.get_child(i) == page:
# TODO There seem to be a Godot bug, tab titles don't always update unless you click on them Oo
print("Set tab title ", title)
_translation_tab_container.set_tab_title(i, title)
return
# Something bad happened
assert(false)
func get_current_language():
var page = _translation_tab_container.get_current_tab_control()
for language in _translation_edits:
if _translation_edits[language] == page:
return language
# Something bad happened
assert(false)
return null
func save_file(filepath): func save_file(filepath):
var ext = filepath.get_extension() var ext = filepath.get_extension()
var saved_languages = []
if ext == "po": if ext == "po":
PoLoader.save_po_translations(filepath.get_base_dir(), _data, _languages) var languages_to_save = _modified_languages.keys()
saved_languages = PoLoader.save_po_translations(filepath.get_base_dir(), _data, languages_to_save)
elif ext == "csv": elif ext == "csv":
CsvLoader.save_csv_translation(_data) saved_languages = CsvLoader.save_csv_translation(filepath, _data)
else: else:
printerr("Unknown file format, cannot save ", filepath) printerr("Unknown file format, cannot save ", filepath)
for language in saved_languages:
_set_language_unmodified(language)
_current_file = filepath
func refresh_list(): func refresh_list():
_string_list.clear() _string_list.clear()
@ -160,6 +282,7 @@ func _on_StringList_item_selected(index):
var s = _data[str_id] var s = _data[str_id]
for language in _languages: for language in _languages:
var e = _translation_edits[language] var e = _translation_edits[language]
e.show()
if s.translations.has(language): if s.translations.has(language):
e.text = s.translations[language] e.text = s.translations[language]
else: else:
@ -196,10 +319,16 @@ func _on_StringEditionDialog_submitted(str_id, prev_str_id):
func _validate_new_string_id(str_id): func _validate_new_string_id(str_id):
if _data.has(str_id): if _data.has(str_id):
return "Already existing" return "Already existing"
if str_id.strip_edges() != str_id:
return "Must not start or end with spaces"
for k in _data:
if k.nocasecmp_to(str_id) == 0:
return "Already existing with different case"
return true return true
func add_new_string(strid): func add_new_string(strid):
print("Adding new string ", strid)
assert(not _data.has(strid)) assert(not _data.has(strid))
var s = { var s = {
"translations": {}, "translations": {},
@ -219,3 +348,37 @@ func rename_string(old_strid, new_strid):
_string_list.set_item_text(i, new_strid) _string_list.set_item_text(i, new_strid)
break break
func _add_language(language):
assert(_languages.find(language) == -1)
_create_translation_edit(language)
_languages.append(language)
_set_language_modified(language)
var menu_index = _file_menu.get_popup().get_item_index(MENU_FILE_REMOVE_LANGUAGE)
_file_menu.get_popup().set_item_disabled(menu_index, false)
print("Added language ", language)
func _remove_language(language):
assert(_languages.find(language) != -1)
_set_language_unmodified(language)
var edit = _translation_edits[language]
edit.queue_free()
_translation_edits.erase(language)
_languages.erase(language)
if len(_languages) == 0:
var menu_index = _file_menu.get_popup().get_item_index(MENU_FILE_REMOVE_LANGUAGE)
_file_menu.get_popup().set_item_disabled(menu_index, true)
print("Removed language ", language)
func _on_RemoveLanguageConfirmationDialog_confirmed():
var language = get_current_language()
_remove_language(language)

View File

@ -3,7 +3,7 @@
[ext_resource path="res://addons/zylann.translation_editor/tools/translation_editor.gd" type="Script" id=1] [ext_resource path="res://addons/zylann.translation_editor/tools/translation_editor.gd" type="Script" id=1]
[ext_resource path="res://addons/zylann.translation_editor/tools/icons/icon_save.svg" type="Texture" id=2] [ext_resource path="res://addons/zylann.translation_editor/tools/icons/icon_save.svg" type="Texture" id=2]
[node name="TranslationEditor" type="Panel" index="0"] [node name="TranslationEditor" type="Panel"]
anchor_left = 0.0 anchor_left = 0.0
anchor_top = 0.0 anchor_top = 0.0
@ -432,7 +432,7 @@ caret_block_mode = false
caret_blink = false caret_blink = false
caret_blink_speed = 0.65 caret_blink_speed = 0.65
caret_moving_by_right_click = true caret_moving_by_right_click = true
_sections_unfolded = [ "Size Flags" ] _sections_unfolded = [ "Rect", "Size Flags" ]
[node name="StatusBar" type="HBoxContainer" parent="VBoxContainer" index="2"] [node name="StatusBar" type="HBoxContainer" parent="VBoxContainer" index="2"]
@ -480,4 +480,6 @@ max_lines_visible = -1
[connection signal="pressed" from="VBoxContainer/Main/LeftPane/StringListActions/RenameButton" to="." method="_on_RenameButton_pressed"] [connection signal="pressed" from="VBoxContainer/Main/LeftPane/StringListActions/RenameButton" to="." method="_on_RenameButton_pressed"]
[connection signal="text_changed" from="VBoxContainer/Main/RightPane/VSplitContainer/VBoxContainer/NotesEdit" to="." method="_on_NotesEdit_text_changed"]