summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llui/llspellcheck.cpp45
-rw-r--r--indra/llui/llspellcheck.h5
-rw-r--r--indra/newview/llfilepicker.cpp22
-rw-r--r--indra/newview/llfilepicker.h1
-rw-r--r--indra/newview/llfloaterspellchecksettings.cpp127
-rw-r--r--indra/newview/llfloaterspellchecksettings.h25
-rw-r--r--indra/newview/llviewerfloaterreg.cpp1
-rw-r--r--indra/newview/skins/default/xui/en/floater_spellcheck.xml10
-rw-r--r--indra/newview/skins/default/xui/en/floater_spellcheck_import.xml116
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml1
10 files changed, 335 insertions, 18 deletions
diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp
index bde3b56741..04c8a4fed0 100644
--- a/indra/llui/llspellcheck.cpp
+++ b/indra/llui/llspellcheck.cpp
@@ -88,32 +88,63 @@ S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::str
}
// static
-const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name)
+const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language)
{
for (LLSD::array_const_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
{
const LLSD& dict_entry = *it;
- if (dict_name == dict_entry["language"].asString())
+ if (dict_language == dict_entry["language"].asString())
return dict_entry;
}
return LLSD();
}
// static
+void LLSpellChecker::setDictionaryData(const LLSD& dict_info)
+{
+ const std::string dict_language = dict_info["language"].asString();
+ if (dict_language.empty())
+ return;
+
+ for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
+ {
+ LLSD& dict_entry = *it;
+ if (dict_language == dict_entry["language"].asString())
+ {
+ dict_entry = dict_info;
+ return;
+ }
+ }
+ sDictMap.append(dict_info);
+ return;
+}
+
+// static
void LLSpellChecker::refreshDictionaryMap()
{
const std::string app_path = getDictionaryAppPath();
const std::string user_path = getDictionaryUserPath();
// Load dictionary information (file name, friendly name, ...)
- llifstream user_map(user_path + "dictionaries.xml", std::ios::binary);
- if ( (!user_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_map)) || (0 == sDictMap.size()) )
+ llifstream user_file(user_path + "dictionaries.xml", std::ios::binary);
+ if ( (!user_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_file)) || (0 == sDictMap.size()) )
{
- llifstream app_map(app_path + "dictionaries.xml", std::ios::binary);
- if ( (!app_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_map)) || (0 == sDictMap.size()) )
+ llifstream app_file(app_path + "dictionaries.xml", std::ios::binary);
+ if ( (!app_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_file)) || (0 == sDictMap.size()) )
return;
}
+ // Load user installed dictionary information
+ llifstream custom_file(user_path + "user_dictionaries.xml", std::ios::binary);
+ if (custom_file.is_open())
+ {
+ LLSD custom_dict_map;
+ LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file);
+ for (LLSD::array_const_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it)
+ setDictionaryData(*it);
+ custom_file.close();
+ }
+
// Look for installed dictionaries
std::string tmp_app_path, tmp_user_path;
for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
@@ -126,6 +157,8 @@ void LLSpellChecker::refreshDictionaryMap()
sdDict["has_custom"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_CUSTOM_SUFFIX + ".dic"));
sdDict["has_ignore"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_IGNORE_SUFFIX + ".dic"));
}
+
+ sSettingsChangeSignal();
}
void LLSpellChecker::addToCustomDictionary(const std::string& word)
diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h
index d736a7f082..acb121dd19 100644
--- a/indra/llui/llspellcheck.h
+++ b/indra/llui/llspellcheck.h
@@ -59,12 +59,15 @@ public:
static const std::string getDictionaryAppPath();
static const std::string getDictionaryUserPath();
- static const LLSD getDictionaryData(const std::string& dict_name);
+ static const LLSD getDictionaryData(const std::string& dict_language);
static const LLSD& getDictionaryMap() { return sDictMap; }
static bool getUseSpellCheck();
static void refreshDictionaryMap();
static void setUseSpellCheck(const std::string& dict_name);
+protected:
+ static void setDictionaryData(const LLSD& dict_info);
+public:
typedef boost::signals2::signal<void()> settings_change_signal_t;
static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb);
protected:
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 8986a694f9..cbb5a40cfa 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -59,6 +59,7 @@ LLFilePicker LLFilePicker::sInstance;
#define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
#define MODEL_FILTER L"Model files (*.dae)\0*.dae\0"
#define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0"
+#define DICTIONARY_FILTER L"Dictionary files (*.dic)\0*.dic\0"
#endif
//
@@ -218,6 +219,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
mOFN.lpstrFilter = SCRIPT_FILTER \
L"\0";
break;
+ case FFLOAD_DICTIONARY:
+ mOFN.lpstrFilter = DICTIONARY_FILTER \
+ L"\0";
+ break;
default:
res = FALSE;
break;
@@ -643,6 +648,14 @@ Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callB
result = false;
}
}
+ else if (filter == FFLOAD_DICTIONARY)
+ {
+ if (fileInfo.filetype != 'DIC ' &&
+ (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dic"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) )
+ {
+ result = false;
+ }
+ }
if (fileInfo.extension)
{
@@ -1235,6 +1248,12 @@ static std::string add_script_filter_to_gtkchooser(GtkWindow *picker)
LLTrans::getString("script_files") + " (*.lsl)");
}
+static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker)
+{
+ return add_simple_mime_filter_to_gtkchooser(picker, "text/plain",
+ LLTrans::getString("dictionary_files") + " (*.dic)");
+}
+
BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
{
BOOL rtn = FALSE;
@@ -1371,6 +1390,9 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
case FFLOAD_SCRIPT:
filtername = add_script_filter_to_gtkchooser(picker);
break;
+ case FFLOAD_DICTIONARY:
+ filtername = add_dictionary_filter_to_gtkchooser(picker);
+ break;
default:;
break;
}
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index a4d5d68ff5..55c665b9c7 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -85,6 +85,7 @@ public:
FFLOAD_MODEL = 9,
FFLOAD_COLLADA = 10,
FFLOAD_SCRIPT = 11,
+ FFLOAD_DICTIONARY = 12
};
enum ESaveFilter
diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp
index ff5afc8169..8bf480c4df 100644
--- a/indra/newview/llfloaterspellchecksettings.cpp
+++ b/indra/newview/llfloaterspellchecksettings.cpp
@@ -27,13 +27,19 @@
#include "llviewerprecompiledheaders.h"
#include "llcombobox.h"
+#include "llfilepicker.h"
+#include "llfloaterreg.h"
#include "llfloaterspellchecksettings.h"
#include "llscrolllistctrl.h"
+#include "llsdserialize.h"
#include "llspellcheck.h"
#include "llviewercontrol.h"
#include <boost/algorithm/string.hpp>
+///----------------------------------------------------------------------------
+/// Class LLFloaterSpellCheckerSettings
+///----------------------------------------------------------------------------
LLFloaterSpellCheckerSettings::LLFloaterSpellCheckerSettings(const LLSD& key)
: LLFloater(key)
{
@@ -42,21 +48,28 @@ LLFloaterSpellCheckerSettings::LLFloaterSpellCheckerSettings(const LLSD& key)
BOOL LLFloaterSpellCheckerSettings::postBuild(void)
{
gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false));
+ LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange, this));
+ getChild<LLUICtrl>("spellcheck_import_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnImport, this));
getChild<LLUICtrl>("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false));
- getChild<LLUICtrl>("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onClickDictMove, this, "spellcheck_active_list", "spellcheck_available_list"));
- getChild<LLUICtrl>("spellcheck_moveright_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onClickDictMove, this, "spellcheck_available_list", "spellcheck_active_list"));
- getChild<LLUICtrl>("spellcheck_ok")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onOK, this));
- getChild<LLUICtrl>("spellcheck_cancel")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onCancel, this));
+ getChild<LLUICtrl>("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_active_list", "spellcheck_available_list"));
+ getChild<LLUICtrl>("spellcheck_moveright_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_available_list", "spellcheck_active_list"));
+ getChild<LLUICtrl>("spellcheck_ok")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnOK, this));
+ getChild<LLUICtrl>("spellcheck_cancel")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnCancel, this));
return true;
}
-void LLFloaterSpellCheckerSettings::onCancel()
+void LLFloaterSpellCheckerSettings::onBtnCancel()
{
closeFloater(false);
}
-void LLFloaterSpellCheckerSettings::onClickDictMove(const std::string& from, const std::string& to)
+void LLFloaterSpellCheckerSettings::onBtnImport()
+{
+ LLFloaterReg::showInstance("prefs_spellchecker_import");
+}
+
+void LLFloaterSpellCheckerSettings::onBtnMove(const std::string& from, const std::string& to)
{
LLScrollListCtrl* from_ctrl = findChild<LLScrollListCtrl>(from);
LLScrollListCtrl* to_ctrl = findChild<LLScrollListCtrl>(to);
@@ -75,7 +88,7 @@ void LLFloaterSpellCheckerSettings::onClickDictMove(const std::string& from, con
from_ctrl->deleteSelectedItems();
}
-void LLFloaterSpellCheckerSettings::onOK()
+void LLFloaterSpellCheckerSettings::onBtnOK()
{
std::list<std::string> list_dict;
@@ -100,6 +113,11 @@ void LLFloaterSpellCheckerSettings::onOpen(const LLSD& key)
refreshDictionaryLists(true);
}
+void LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange()
+{
+ refreshDictionaryLists(true);
+}
+
void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings)
{
bool enabled = gSavedSettings.getBOOL("SpellCheck");
@@ -177,3 +195,98 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings)
}
}
}
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterSpellCheckerImport
+///----------------------------------------------------------------------------
+LLFloaterSpellCheckerImport::LLFloaterSpellCheckerImport(const LLSD& key)
+ : LLFloater(key)
+{
+}
+
+BOOL LLFloaterSpellCheckerImport::postBuild(void)
+{
+ getChild<LLUICtrl>("dictionary_path_browse")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnBrowse, this));
+ getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnOK, this));
+ getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnCancel, this));
+
+ return true;
+}
+
+void LLFloaterSpellCheckerImport::onBtnBrowse()
+{
+ LLFilePicker& file_picker = LLFilePicker::instance();
+ if (!file_picker.getOpenFile(LLFilePicker::FFLOAD_DICTIONARY))
+ {
+ return;
+ }
+
+ const std::string filepath = file_picker.getFirstFile();
+ getChild<LLUICtrl>("dictionary_path")->setValue(filepath);
+
+ mDictionaryDir = gDirUtilp->getDirName(filepath);
+ mDictionaryBasename = gDirUtilp->getBaseFileName(filepath, true);
+ getChild<LLUICtrl>("dictionary_name")->setValue(mDictionaryBasename);
+}
+
+void LLFloaterSpellCheckerImport::onBtnCancel()
+{
+ closeFloater(false);
+}
+
+void LLFloaterSpellCheckerImport::onBtnOK()
+{
+ const std::string dict_dic = mDictionaryDir + gDirUtilp->getDirDelimiter() + mDictionaryBasename + ".dic";
+ const std::string dict_aff = mDictionaryDir + gDirUtilp->getDirDelimiter() + mDictionaryBasename + ".aff";
+ std::string dict_language = getChild<LLUICtrl>("dictionary_language")->getValue().asString();
+ LLStringUtil::trim(dict_language);
+ if ( (dict_language.empty()) || (!gDirUtilp->fileExists(dict_dic)) ||
+ (mDictionaryDir.empty()) || (mDictionaryBasename.empty()) )
+ {
+ return;
+ }
+
+ LLSD custom_dict_info;
+ custom_dict_info["is_primary"] = (bool)gDirUtilp->fileExists(dict_aff);
+ custom_dict_info["name"] = mDictionaryBasename;
+ custom_dict_info["language"] = dict_language;
+
+ LLSD custom_dict_map;
+ llifstream custom_file_in(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml");
+ if (custom_file_in.is_open())
+ {
+ LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file_in);
+ custom_file_in.close();
+ }
+
+ LLSD::array_iterator it = custom_dict_map.beginArray();
+ for (; it != custom_dict_map.endArray(); ++it)
+ {
+ LLSD& dict_info = *it;
+ if (dict_info["name"].asString() == mDictionaryBasename)
+ {
+ dict_info = custom_dict_info;
+ break;
+ }
+ }
+ if (custom_dict_map.endArray() == it)
+ {
+ custom_dict_map.append(custom_dict_info);
+ }
+
+ llofstream custom_file_out(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml", std::ios::trunc);
+ if (custom_file_out.is_open())
+ {
+ LLSDSerialize::toPrettyXML(custom_dict_map, custom_file_out);
+ custom_file_out.close();
+ }
+
+ LLFile::rename(dict_dic, LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".dic");
+ if (gDirUtilp->fileExists(dict_aff))
+ {
+ LLFile::rename(dict_aff, LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".aff");
+ }
+ LLSpellChecker::refreshDictionaryMap();
+
+ closeFloater(false);
+}
diff --git a/indra/newview/llfloaterspellchecksettings.h b/indra/newview/llfloaterspellchecksettings.h
index 2fbf47617a..3a4428d4c3 100644
--- a/indra/newview/llfloaterspellchecksettings.h
+++ b/indra/newview/llfloaterspellchecksettings.h
@@ -38,11 +38,28 @@ public:
/*virtual*/ void onOpen(const LLSD& key);
protected:
- void onCancel();
- void onClickDictMove(const std::string& from, const std::string& to);
- void onOK();
- void onSave();
+ void onBtnCancel();
+ void onBtnImport();
+ void onBtnMove(const std::string& from, const std::string& to);
+ void onBtnOK();
+ void onSpellCheckSettingsChange();
void refreshDictionaryLists(bool from_settings);
};
+class LLFloaterSpellCheckerImport : public LLFloater
+{
+public:
+ LLFloaterSpellCheckerImport(const LLSD& key);
+
+ /*virtual*/ BOOL postBuild();
+
+protected:
+ void onBtnBrowse();
+ void onBtnCancel();
+ void onBtnOK();
+
+ std::string mDictionaryDir;
+ std::string mDictionaryBasename;
+};
+
#endif // LLFLOATERSPELLCHECKERSETTINGS_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 4d84262a3a..8d716a7317 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -249,6 +249,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>);
LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHardwareSettings>);
+ LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>);
LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>);
LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerSettings>);
LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAutoReplaceSettings>);
diff --git a/indra/newview/skins/default/xui/en/floater_spellcheck.xml b/indra/newview/skins/default/xui/en/floater_spellcheck.xml
index bd3f60cf4a..91639ed0da 100644
--- a/indra/newview/skins/default/xui/en/floater_spellcheck.xml
+++ b/indra/newview/skins/default/xui/en/floater_spellcheck.xml
@@ -53,6 +53,16 @@
top_pad="-15"
width="175"
/>
+ <button
+ follows="left|top"
+ height="23"
+ label="Import"
+ label_selected="Import"
+ layout="topleft"
+ left_pad="5"
+ name="spellcheck_import_btn"
+ top_delta="0"
+ width="75" />
<text
enabled_control="SpellCheck"
follows="top|left"
diff --git a/indra/newview/skins/default/xui/en/floater_spellcheck_import.xml b/indra/newview/skins/default/xui/en/floater_spellcheck_import.xml
new file mode 100644
index 0000000000..b54090015d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_spellcheck_import.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ border="true"
+ can_close="true"
+ can_minimize="true"
+ bottom="275"
+ left="300"
+ can_resize="false"
+ height="140"
+ width="400"
+ name="spellcheck_import"
+ title="Import Dictionary">
+ <text
+ follows="top|left"
+ height="16"
+ layout="topleft"
+ left="25"
+ top="15"
+ type="string"
+ width="65">
+ Dictionary:
+ </text>
+ <line_editor
+ enabled="false"
+ follows="left|top"
+ height="23"
+ layout="topleft"
+ left_pad="10"
+ max_length_bytes="255"
+ name="dictionary_path"
+ top_delta="-5"
+ width="200" />
+ <button
+ follows="left|top"
+ height="23"
+ label="Browse"
+ label_selected="Browse"
+ layout="topleft"
+ left_pad="5"
+ name="dictionary_path_browse"
+ top_delta="0"
+ width="75" />
+ <text
+ follows="top|left"
+ height="16"
+ layout="topleft"
+ left="25"
+ top_pad="8"
+ type="string"
+ width="65">
+ Name:
+ </text>
+ <line_editor
+ enabled="false"
+ follows="left|top"
+ height="23"
+ layout="topleft"
+ left_pad="10"
+ max_length_bytes="255"
+ name="dictionary_name"
+ top_delta="-5"
+ width="200" />
+ <text
+ follows="top|left"
+ height="16"
+ layout="topleft"
+ left="25"
+ top_pad="8"
+ type="string"
+ width="65">
+ Language:
+ </text>
+ <line_editor
+ follows="left|top"
+ height="23"
+ layout="topleft"
+ left_pad="10"
+ max_length_bytes="255"
+ name="dictionary_language"
+ top_delta="-5"
+ width="200" />
+ <view_border
+ top_pad="10"
+ left="2"
+ height="0"
+ width="396"
+ follows="left|top"
+ bevel_style="none"
+ border_thickness="1"
+ mouse_opaque="false"
+ name="divisor"/>
+ <button
+ top_pad="10"
+ right="280"
+ height="22"
+ width="90"
+ enabled="true"
+ follows="left|top"
+ mouse_opaque="true"
+ halign="center"
+ scale_image="true"
+ name="ok_btn"
+ label="Import" />
+ <button
+ top_delta="0"
+ right="380"
+ height="22"
+ width="90"
+ enabled="true"
+ follows="left|top"
+ mouse_opaque="true"
+ halign="center"
+ scale_image="true"
+ name="cancel_btn"
+ label="Cancel" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 4ccec4838a..4b58df595f 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -440,6 +440,7 @@ Please try logging in again in a minute.</string>
<string name="load_files">Load Files</string>
<string name="choose_the_directory">Choose Directory</string>
<string name="script_files">Scripts</string>
+ <string name="dictionary_files">Dictionaries</string>
<!-- LSL Usage Hover Tips -->
<!-- NOTE: For now these are set as translate="false", until DEV-40761 is implemented (to internationalize the rest of tooltips in the same window).