+
+
+
+
+
+ - Kibod
+ - Kibodyere
+
+
+
+ - Other Input Method
+ - Other Input Methods
+
+
+ Dzakǝr Kibod Ɓǝlin
+
+ Nyayere Namtǝ Ndǝ Vu
+
+ %1$s Settingyere
+
+ Pukǝr
+
+ Mwari tubwa hi
+
+ Kansǝl
+
+ Harti
+
+ Harti Keyman
+
+ Alǝkǝma
+
+ Whalǝr ʻYati su Alǝkǝma
+
+ Sǝgǝl akǝr
+
+ Vu ko hau
+
+ Aɦǝla saka nkiɗu
+
+ Akǝma
+
+ Kal kal
+
+ Update
+
+ Adi ata mǝzi ɓui ka lukwa Keyman server wɛ!
+
+ Gada bara ɗlǝba ka ɗalba kibod ǝni ya?
+
+ Gada bara download vershon nam ɓǝlin nǝr kibod ǝni ya?
+
+ Gada bara ka update kibodyere ba and dictionariyere kulini ya?
+
+ Updateyere nǝr sǝr kǝthlǝr
+
+ Updateyere Nǝr Sǝr Kǝthlǝr Nam Adai
+
+ %1$s (Updateyer Nam Adai)
+
+ Updateyere nam adai nǝr kibod %1$s: %2$s
+
+ Updateyere nam adai nǝr dictionary %1$s: %2$s
+
+ Vershon nǝr kibod
+
+ Link nǝr dlarɛ
+
+ Faba ka ɗalba kibod
+
+ [new] %1$s
+
+ Skanba code ǝni akuya ka gǝ vu ǝni akwa\nkeyboard divais damwa
+
+ Usɛ aka si akwa %1$s
+
+ Gada bara library nǝr FileProvider akuyaka gǝ wul su akwa fail nǝr dlarɛ: %1$s
+
+ Fatal keyboard error with %1$s:%2$s for %3$s language. Loading default keyboard.
+
+ Su kura kal kalakwa kibod %1$s:%2$s nǝr %3$s nya.
+
+ Ata kǝra chakǝnta akuyaka ɓui suyere tara tsukwar bwar dictionary kadǝbar ka ndǝ download ko sǝgǝl akǝr
+
+ Gada bara download vershon nam ɓǝlin nǝr kibod ǝni ya?
+
+ Dictionary adiwɛ akuya ka ndǝ download
+
+ Katalog nǝr dlarɛ adiwɛ
+
+ Update nǝr Katalog badicini akwa background
+
+ Katalogari tsu ata kǝra downloading; usɛ ɓǝla dzakti nkǝrti aɦǝla saka nkiɗu laka kadwam!
+
+ Ata kǝra chakǝnta ka bara sǝr ampaniyere wato resource
+
+ Downloading keyboard badicini akwa Background
+
+ Kibodnamtǝ gǝ tsarba ata kǝra downloading; usɛ dzakti nkǝrti kadawm aɦǝla saka nkiɗu laka!
+
+ Keyboard download kǝ kuri!
+
+ Downloading dictionary kǝ Badicini Aɦǝli
+
+ Kibod namtǝ gǝ tsarba ata kǝra downloading; usɛ dzakti nkǝrti kadawm aɦǝla saka nkiɗu laka!
+
+ Keyboard download kǝ kuri.
+
+ Download ta mǝzi ʻya wɛ
+
+ Ta ɓui ka download fail wɛ
+
+ Ta ɓui ka lukwa server wɛ!
+
+ "Shanga suyere nam adai ani up to date!"
+
+ Duku akwa ko hang ta ǝniyere ngǝlata ʻya update!
+
+ Sǝr kǝthlǝryere nam adai kǝ ʻya update kal kal!
+
+ Version nǝr Dictionary
+
+ Kǝlba ka ɗalba dictionary
+
+ Gada bara kǝlba ka ɗalba dictionary ǝni ya?
+
+ %1$s ndǝ kurta vu kibod
+
+ Mǝrti ka dza mǝzi ʻyati ka dzǝ dzukti suwar su wato correctionyere
+
+ Enable predictions
+
+ Dictionary
+
+ Baraba ka zǝndi dictionary nam adai
+
+ Dictionary: %1$s
+
+ %1$s dictionariyere
+
+
+ Dictionary namtǝ ndǝ vu ko hau
+
+
+ - (%1$d kibod)
+ - (%1$d kibodyere)
+
+
+ Default Locale
+
+
+
+ Kǝlba ka ɗalba
+
+
+ Tsukwar vi ǝni akuya ka gǝ pali kibod
+
diff --git a/android/KMEA/app/src/main/res/values-hia-rNG/strings.xml b/android/KMEA/app/src/main/res/values-hia-rNG/strings.xml
new file mode 100644
index 0000000000..d1e85bc0df
--- /dev/null
+++ b/android/KMEA/app/src/main/res/values-hia-rNG/strings.xml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+ - Keyboardina ta faftal jiv tadiye k vinda an kompitaina ta faftal jiv tadiye k vinda an kompita
+ - Keyboardina ta faftal jiv tadiye k vinda an kompitaina ta faftal jiv tadiye k vinda an kompita
+ - Keyboardina ta faftal jiv tadiye k vinda an kompitaina ta faftal jiv tadiye k vinda an kompita
+
+
+
+ - Other Input Methods
+ - Other Input Method
+ - Other Input Methods
+
+
+ A mbakat wuliwa Keyboard
+
+ Gwaɗaha luwahunda fanlo
+
+ %1$s Settings
+
+ Mbakata
+
+ Uhili
+
+ Jata
+
+ Funta
+
+ Funt Keyman
+
+ Mbakata jeb t kima
+
+ Next Input Method
+
+ Sangata
+
+ Fanta
+
+ Peɗe
+
+ Unda siɗi
+
+ Muvaya
+
+ Haf tinunda sa magalo
+
+ Ha da gwaghva nda Keyman server wo!
+
+ Ɗow ka k masunt tana keyboard na re?
+
+ Ɗow ka k sangat tina wuliwa tana keyboard na re?
+
+ Ɗow ka k haf tinunda sa magalo sakoro t keyboards na nda dictionaries na kana re?
+
+ Resource Updates
+
+ Resource Updates hahaɗe
+
+ %1$s (Update hahaɗe)
+
+ Updates hahaɗe anga keyboard %1$s: %2$s
+
+ Updates hahaɗe anga dictionary %1$s: %2$s
+
+ Keyboard version
+
+ Help link
+
+ Fan bol t keyboard wo
+
+ [new] %1$s
+
+ Afkla fota nana code na anga klaf tana \nkeyboard tundaha sakwiɗi
+
+ Uss nda sukagha da vila %1$s
+
+ FileProvider library needed to view help file: %1$s
+
+ Fatal keyboard nda kuskure %1$s:%2$s anga %3$s gwaɗaha luwa. Kalt girgira keyboard.
+
+ Kuskure an keyboard %1$s:%2$s for %3$s gwaɗa luwa.
+
+ Naghata anga gwaft dictionary da sangata
+
+ Ɗow ka k sangat wuliwa nana dictionary na re?
+
+ Ha dictionary k sangatawo
+
+ The resource catalog is unavailable
+
+ Catalog update started in background
+
+ Ana catalog nana hma t sangata; Gamsa an tika pighata hiɗeka!
+
+ Nagha tinaha
+
+ Sangat keyboard fuɗata an Background
+
+ Key board unda klafal na fuɗa fuɗa sangata; Gamsa an tika pighata hiɗeka!
+
+ Keyboard kakiɗa sangata!
+
+ Sangat dictionary fuɗa fuɗa an Background
+
+ Dictionary unda klafal na fuɗa fuɗa sangata; gamsa an tika pighata hiɗeka!
+
+ Dictionary kakiɗa sangata.
+
+ Sanga buwo
+
+ Kalavukala k thlighaft file unda sangalo
+
+ Javabt wativa kusat server wo!
+
+ "Sma inaha nganana ɗughwana!"
+
+ Tala ko kada inaha kol ɗughwana!
+
+ Inaha ngana maga magal saʻa ɗughwanukini!
+
+ Dictionary version
+
+ Fan bol t dictionary wo
+
+ Ɗow ka k masun tana dictionary na re?
+
+ %1$s keyboard fan falo
+
+ Magaghva virata magata
+
+ Enable predictions
+
+ Dictionary
+
+ A nighat dictionary unda hahaɗe
+
+ Dictionary: %1$s
+
+ %1$s dictionaries
+
+
+ Dictionary fan falo
+
+
+ - (%1$d keyboards)
+ - (%1$d keyboard)
+ - (%1$d keyboards)
+
+
+ Default Locale
+
+
+
+ Masata
+
+
+ Aff fa jiv ahdina ka mbiɗat keyboard
+
diff --git a/android/KMEA/app/src/main/res/values-mrt-rNG/strings.xml b/android/KMEA/app/src/main/res/values-mrt-rNG/strings.xml
new file mode 100644
index 0000000000..b50d31db44
--- /dev/null
+++ b/android/KMEA/app/src/main/res/values-mrt-rNG/strings.xml
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+ - Keyboard
+ - Keyboard
+
+
+
+ - Other Input Method
+ - Other Input Methods
+
+
+ Mchaku Keyboard bilin
+
+ Fia Ŋya ari yer
+
+ %1$s Settings
+
+ Mchaku
+
+ Yikuɗu
+
+ Kukulna
+
+ Ghaɗu
+
+ Ghaɗu Keyman
+
+ Ladaŋwa
+
+ Lagu fia ruɓutsini adaŋwa
+
+ Download
+
+ Install
+
+ Asikari
+
+ Nagum
+
+ OK
+
+ Update
+
+ Accitu connect anu Keyman server mai!
+
+ Nagu ayu ga kukulna keyboard ari ya?
+
+ Nagu ayu ga download version bilin nur keyboard ya?
+
+ Nagu ayu ga update anu keyboard baɗa dictionaries yer abang?
+
+ Updates nur resource
+
+ Updates nur Resource aʻi
+
+ %1$s (Update aʻi)
+
+ Updates aʻi anu keyboard %1$s: %2$s
+
+ Updates aʻi anu dictionary %1$s: %2$s
+
+ Version nur keyman
+
+ Help link
+
+ Uninstall keyboard
+
+ [bilin] %1$s
+
+ Scan this code to load this\nkeyboard on another device
+
+ Usi ga shili %1$s
+
+ FileProvider library needed to view help file: %1$s
+
+ Fatal keyboard error with %1$s:%2$s for %3$s language. Loading default keyboard.
+
+ Ŋya nur keyboard %1$s:%2$s anu %3$s kra kalkal.
+
+ Luba dictionary kuku nagu acittu downloadi
+
+ Nagu ayu ga download version bilin nur dictionary ya?
+
+ Dictionary aʻi mai ga download
+
+ Catalog nur kari yer aʻi mai
+
+ Catalog update started in background
+
+ Catalog tsu naja vur downloading; manki kuga bura ngilaba!
+
+ Luba kari yer
+
+ Downloading keyboard a baditsini akwa Background
+
+ Keyboard dun mji a caɗu naja vur dowloadi manki bura ngilaba u latu kushu!
+
+ Keyboard download akuɗuri!
+
+ Downloading dictionary a baditsini akwa Background
+
+ Dictionary kuku dun mji a caɗu naja vur downloadi: manki ngilaba u latu kushu!
+
+ Download nur dictionary akuɗuri.
+
+ Download a ngiliri
+
+ Acittu ziba aga file dun mji a iu download
+
+ Acittu gwa kwa server mai!
+
+ "Ca thlir ari nanda bilin!"
+
+ Resources pathlu akiya mai mithlu a ngil ga iu update!
+
+ Resources successfully updated!
+
+ Dictionary version
+
+ Uninstall dictionary
+
+ Nagu ayu ga kukulna dictionary ya?
+
+ %1$s keyboard installed
+
+ Enable corrections
+
+ Enable predictions
+
+ Dictionary
+
+ Kutu ma dictionary aʻi
+
+ Dictionary: %1$s
+
+ %1$s dictionaries
+
+
+ Dictionary installed
+
+
+ - (%1$d keyboard)
+ - (%1$d keyboards)
+
+
+ Default Locale
+
+
+
+ Kukulna
+
+
+ Ncina ga pubila keyboard
+
diff --git a/common/core/desktop/src/km_kbp_state_api.cpp b/common/core/desktop/src/km_kbp_state_api.cpp
index 674923efab..1d750536d7 100644
--- a/common/core/desktop/src/km_kbp_state_api.cpp
+++ b/common/core/desktop/src/km_kbp_state_api.cpp
@@ -70,7 +70,7 @@ km_kbp_context *km_kbp_state_context(km_kbp_state *state)
}
km_kbp_status kbp_state_get_intermediate_context(
- km_kbp_state *state,
+ km_kbp_state *state,
km_kbp_context_item ** context_items
) {
assert(state);
@@ -116,7 +116,7 @@ km_kbp_status km_kbp_state_queue_action_items(
return KM_KBP_STATUS_INVALID_ARGUMENT;
}
- if (!processor.queue_action(action_items)) {
+ if (!processor.queue_action(state, action_items)) {
return KM_KBP_STATUS_KEY_ERROR;
}
}
diff --git a/common/core/desktop/src/kmx/kmx_file.h b/common/core/desktop/src/kmx/kmx_file.h
index dffd56b45c..c8d591f25d 100644
--- a/common/core/desktop/src/kmx/kmx_file.h
+++ b/common/core/desktop/src/kmx/kmx_file.h
@@ -110,6 +110,8 @@ namespace kmx {
#define TSS_COMPARISON 30
+#define TSS__KEYMAN_80_MAX 30
+
/* Keyman 9.0 system stores */
#define TSS_PLATFORM 31
@@ -126,7 +128,23 @@ namespace kmx {
#define TSS_TARGETS 38
-#define TSS__MAX 38
+#define TSS__KEYMAN_90_MAX 38
+
+/* Keyman 14.0 system stores */
+
+#define TSS_CASEDKEYS 39
+
+#define TSS__KEYMAN_140_MAX 39
+
+/* Keyman 15.0 system stores */
+
+#define TSS_BEGIN_NEWCONTEXT 40
+#define TSS_BEGIN_POSTKEYSTROKE 41
+#define TSS_LAYERCHANGED 42
+
+#define TSS__KEYMAN_150_MAX 42
+
+#define TSS__MAX 42
/* wm_keyman_control_internal message control codes */
diff --git a/common/core/desktop/src/kmx/kmx_processor.cpp b/common/core/desktop/src/kmx/kmx_processor.cpp
index e66ad10a8b..d4c1f3ff8b 100644
--- a/common/core/desktop/src/kmx/kmx_processor.cpp
+++ b/common/core/desktop/src/kmx/kmx_processor.cpp
@@ -103,7 +103,9 @@ kmx_processor::update_option(
return option(scope, key, value);
}
-bool kmx_processor::queue_action(
+bool
+kmx_processor::queue_action(
+ km_kbp_state * state,
km_kbp_action_item const * action_item
) {
switch (action_item->type) {
@@ -136,11 +138,17 @@ bool kmx_processor::queue_action(
break;
}
case KM_KBP_IT_PERSIST_OPT:
- case KM_KBP_IT_EMIT_KEYSTROKE:
case KM_KBP_IT_CAPSLOCK:
DebugLog("kmx_processor::queue_action: Warning handling of action type [%d] not implented \n", action_item->type);
return false;
break;
+ case KM_KBP_IT_EMIT_KEYSTROKE:
+ // By pass the kmx processor and put this action into the core queue immediately
+ // This has to be done as the kmx processor QueAction does not have an
+ // emit key stroke type.
+ // currently only supporting emitting the current key stroke
+ state->actions().push_emit_keystroke();
+ break;
case KM_KBP_IT_INVALIDATE_CONTEXT:
_kmx.GetActions()->QueueAction(QIT_INVALIDATECONTEXT, 0);
break;
diff --git a/common/core/desktop/src/kmx/kmx_processor.hpp b/common/core/desktop/src/kmx/kmx_processor.hpp
index 67779ac494..0107d45f85 100644
--- a/common/core/desktop/src/kmx/kmx_processor.hpp
+++ b/common/core/desktop/src/kmx/kmx_processor.hpp
@@ -60,7 +60,11 @@ namespace kbp
km_kbp_state *state
) override;
- bool queue_action(km_kbp_action_item const* action_item) override;
+ bool
+ queue_action(
+ km_kbp_state * state,
+ km_kbp_action_item const* action_item
+ ) override;
km_kbp_context_item * get_intermediate_context() override;
diff --git a/common/core/desktop/src/mock/mock_processor.cpp b/common/core/desktop/src/mock/mock_processor.cpp
index e7573975ea..5bd68139e2 100644
--- a/common/core/desktop/src/mock/mock_processor.cpp
+++ b/common/core/desktop/src/mock/mock_processor.cpp
@@ -114,9 +114,15 @@ namespace km {
return KM_KBP_STATUS_OK;
}
- bool mock_processor::queue_action(km_kbp_action_item const* action_item) {
+ bool mock_processor::queue_action(
+ km_kbp_state * state,
+ km_kbp_action_item const* action_item
+ )
+ {
+ assert(state);
assert(action_item);
- // TODO Implement
+ if ((!state) || (!action_item))
+ return false;
return false;
}
diff --git a/common/core/desktop/src/mock/mock_processor.hpp b/common/core/desktop/src/mock/mock_processor.hpp
index fef48298eb..a8aa3f1acc 100644
--- a/common/core/desktop/src/mock/mock_processor.hpp
+++ b/common/core/desktop/src/mock/mock_processor.hpp
@@ -53,7 +53,10 @@ namespace kbp
km_kbp_status process_queued_actions( km_kbp_state *state) override;
- bool queue_action(km_kbp_action_item const* action_item) override;
+ bool queue_action(
+ km_kbp_state * state,
+ km_kbp_action_item const* action_item
+ ) override;
km_kbp_context_item * get_intermediate_context() override;
diff --git a/common/core/desktop/src/processor.hpp b/common/core/desktop/src/processor.hpp
index f7dfaeb28f..d68343ce96 100644
--- a/common/core/desktop/src/processor.hpp
+++ b/common/core/desktop/src/processor.hpp
@@ -75,11 +75,15 @@ namespace kbp
/**
* Add the action items to this keyboard processor queue
*
+ * @param state An opaque pointer to a state object
* @param action_item
* @param bool return true if action item list is successfully processed
*/
virtual bool
- queue_action(km_kbp_action_item const* action_item) = 0;
+ queue_action(
+ km_kbp_state * state,
+ km_kbp_action_item const* action_item
+ ) = 0;
/**
* Returns the keyboardprocessor context as an array of
diff --git a/common/core/desktop/src/rust/rust_mock_processor.cpp b/common/core/desktop/src/rust/rust_mock_processor.cpp
index 100e28cf09..2554d50e7d 100644
--- a/common/core/desktop/src/rust/rust_mock_processor.cpp
+++ b/common/core/desktop/src/rust/rust_mock_processor.cpp
@@ -70,8 +70,15 @@ namespace km {
return KM_KBP_STATUS_OK;
}
- bool rust_mock_processor::queue_action(km_kbp_action_item const* action_item) {
- assert(action_item);
+ bool rust_mock_processor::queue_action(
+ km_kbp_state * state,
+ km_kbp_action_item const* action_item
+ )
+ {
+ assert(state);
+ assert(action_item);
+ if ((!state) || (!action_item))
+ return false;
// TODO Implement
return false;
}
diff --git a/common/core/desktop/src/rust/rust_mock_processor.hpp b/common/core/desktop/src/rust/rust_mock_processor.hpp
index e6187a2e88..5d7cadc6a9 100644
--- a/common/core/desktop/src/rust/rust_mock_processor.hpp
+++ b/common/core/desktop/src/rust/rust_mock_processor.hpp
@@ -50,7 +50,10 @@ namespace kbp
km_kbp_status process_queued_actions( km_kbp_state *state) override;
- bool queue_action(km_kbp_action_item const* action_item) override;
+ bool queue_action(
+ km_kbp_state * state,
+ km_kbp_action_item const* action_item
+ ) override;
km_kbp_context_item * get_intermediate_context() override;
diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json
index 73d28d84e9..102f8473dc 100644
--- a/common/core/web/input-processor/package-lock.json
+++ b/common/core/web/input-processor/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/input-processor",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json
index 8cc7f6d3a5..9b80f962be 100644
--- a/common/core/web/input-processor/package.json
+++ b/common/core/web/input-processor/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/input-processor",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "The core text and prediction processing engine for KeymanWeb",
"repository": {
"type": "git",
@@ -18,8 +18,8 @@
},
"homepage": "https://github.com/keymanapp/keyman#readme",
"devDependencies": {
- "@keymanapp/lexical-model-compiler": "^15.0.177",
- "@keymanapp/resources-gosh": "^15.0.177",
+ "@keymanapp/lexical-model-compiler": "^15.0.184",
+ "@keymanapp/resources-gosh": "^15.0.184",
"@types/node": "^11.9.4",
"chai": "^4.3.4",
"mocha": "^8.4.0",
@@ -34,11 +34,11 @@
"mocha": "mocha"
},
"dependencies": {
- "@keymanapp/keyboard-processor": "^15.0.177",
- "@keymanapp/lexical-model-layer": "^15.0.177",
- "@keymanapp/models-types": "^15.0.177",
- "@keymanapp/web-environment": "^15.0.177",
- "@keymanapp/web-utils": "^15.0.177",
+ "@keymanapp/keyboard-processor": "^15.0.184",
+ "@keymanapp/lexical-model-layer": "^15.0.184",
+ "@keymanapp/models-types": "^15.0.184",
+ "@keymanapp/web-environment": "^15.0.184",
+ "@keymanapp/web-utils": "^15.0.184",
"eventemitter3": "^4.0.0"
}
}
diff --git a/common/core/web/input-processor/src/text/inputProcessor.ts b/common/core/web/input-processor/src/text/inputProcessor.ts
index 501f90ed57..099e36b29d 100644
--- a/common/core/web/input-processor/src/text/inputProcessor.ts
+++ b/common/core/web/input-processor/src/text/inputProcessor.ts
@@ -10,14 +10,16 @@ namespace com.keyman.text {
baseLayout: 'us'
}
+ private device: utils.DeviceSpec;
private kbdProcessor: KeyboardProcessor;
private lngProcessor: prediction.LanguageProcessor;
- constructor(options?: ProcessorInitOptions) {
+ constructor(device: utils.DeviceSpec, options?: ProcessorInitOptions) {
if(!options) {
options = InputProcessor.DEFAULT_OPTIONS;
}
+ this.device = device;
this.kbdProcessor = new KeyboardProcessor(options);
this.lngProcessor = new prediction.LanguageProcessor();
}
@@ -50,11 +52,28 @@ namespace com.keyman.text {
return this.languageProcessor.activeModel;
}
- /**
+ /**
+ * Tell the currently active keyboard that a new context has been selected,
+ * e.g. by focus change, selection change, keyboard change, etc.
+ *
+ * @param {Object} outputTarget The OutputTarget that has focus
+ * @returns {Object} A RuleBehavior object describing the cumulative effects of
+ * all matched keyboard rules
+ */
+ processNewContextEvent(outputTarget: OutputTarget): RuleBehavior {
+ const ruleBehavior = this.keyboardProcessor.processNewContextEvent(this.device, outputTarget);
+
+ if(ruleBehavior) {
+ ruleBehavior.finalize(this.keyboardProcessor, outputTarget);
+ }
+ return ruleBehavior;
+ }
+
+ /**
* Simulate a keystroke according to the touched keyboard button element
*
* Handles default output and keyboard processing for both OSK and physical keystrokes.
- *
+ *
* @param {Object} keyEvent The abstracted KeyEvent to use for keystroke processing
* @param {Object} outputTarget The OutputTarget receiving the KeyEvent
* @returns {Object} A RuleBehavior object describing the cumulative effects of
@@ -105,6 +124,8 @@ namespace com.keyman.text {
// Current, long-existing assumption - it's DOM-backed.
let preInputMock = Mock.from(outputTarget);
+ const startingLayerId = this.keyboardProcessor.layerId;
+
// We presently need the true keystroke to run on the FULL context. That index is still
// needed for some indexing operations when comparing two different output targets.
let ruleBehavior = this.keyboardProcessor.processKeystroke(keyEvent, outputTarget);
@@ -113,7 +134,7 @@ namespace com.keyman.text {
if(keyEvent.kNextLayer) {
this.keyboardProcessor.selectLayer(keyEvent);
}
-
+
// Should we swallow any further processing of keystroke events for this keydown-keypress sequence?
if(ruleBehavior != null) {
let alternates: Alternate[];
@@ -123,7 +144,7 @@ namespace com.keyman.text {
if(this.languageProcessor.isActive && !ruleBehavior.triggersDefaultCommand) {
let keyDistribution = keyEvent.keyDistribution;
- // We don't need to track absolute indexing during alternate-generation;
+ // We don't need to track absolute indexing during alternate-generation;
// only position-relative, so it's better to use a sliding window for context
// when making alternates. (Slightly worse for short text, matters greatly
// for long text.)
@@ -141,7 +162,7 @@ namespace com.keyman.text {
let _globalThis = com.keyman.utils.getGlobalObject();
let timer: () => number;
- // Available by default on `window` in browsers, but _not_ on `global` in Node,
+ // Available by default on `window` in browsers, but _not_ on `global` in Node,
// surprisingly. Since we can't use code dependent on `require` statements
// at present, we have to condition upon it actually existing.
if(_globalThis['performance'] && _globalThis['performance']['now']) {
@@ -152,15 +173,15 @@ namespace com.keyman.text {
TIMEOUT_THRESHOLD = timer() + 16; // + 16ms.
} // else {
// We _could_ just use Date.now() as a backup... but that (probably) only matters
- // when unit testing. So... we actually don't _need_ time thresholding when in
+ // when unit testing. So... we actually don't _need_ time thresholding when in
// a Node environment.
// }
// Tracks a minimum probability for keystroke probability. Anything less will not be
- // included in alternate calculations.
+ // included in alternate calculations.
//
// Seek to match SearchSpace.EDIT_DISTANCE_COST_SCALE from the predictive-text engine.
- // Reasoning for the selected value may be seen there. Short version - keystrokes
+ // Reasoning for the selected value may be seen there. Short version - keystrokes
// that _appear_ very precise may otherwise not even consider directly-neighboring keys.
let KEYSTROKE_EPSILON = Math.exp(-5);
@@ -169,7 +190,7 @@ namespace com.keyman.text {
let activeLayout = this.activeKeyboard.layout(keyEvent.device.formFactor);
alternates = [];
-
+
let totalMass = 0; // Tracks sum of non-error probabilities.
for(let pair of keyDistribution) {
if(pair.p < KEYSTROKE_EPSILON) {
@@ -184,7 +205,7 @@ namespace com.keyman.text {
}
let mock = Mock.from(windowedMock);
-
+
let altKey = activeLayout.getLayer(keyEvent.kbdLayer).getKey(pair.keyId);
if(!altKey) {
console.warn("Potential fat-finger key could not be found in layer!");
@@ -193,14 +214,14 @@ namespace com.keyman.text {
let altEvent = altKey.constructKeyEvent(this.keyboardProcessor, keyEvent.device);
let alternateBehavior = this.keyboardProcessor.processKeystroke(altEvent, mock);
-
+
// If alternateBehavior.beep == true, ignore it. It's a disallowed key sequence,
// so we expect users to never intend their use.
//
// Also possible that this set of conditions fail for all evaluated alternates.
if(alternateBehavior && !alternateBehavior.beep && pair.p > 0) {
let transform: Transform = alternateBehavior.transcription.transform;
-
+
// Ensure that the alternate's token id matches that of the current keystroke, as we only
// record the matched rule's context (since they match)
transform.id = ruleBehavior.transcription.token;
@@ -224,7 +245,7 @@ namespace com.keyman.text {
ruleBehavior.finalize(this.keyboardProcessor, outputTarget);
// -- All keystroke (and 'alternate') processing is now complete. Time to finalize everything! --
-
+
// Notify the ModelManager of new input - it's predictive text time!
if(alternates && alternates.length > 0) {
ruleBehavior.transcription.alternates = alternates;
@@ -237,6 +258,20 @@ namespace com.keyman.text {
// For DOM-aware targets, this will trigger a DOM event page designers may listen for.
outputTarget.doInputEvent();
}
+
+ // The keyboard may want to take an action after all other keystroke processing is
+ // finished, for example to switch layers. This action may not have any output
+ // but may change system store or variable store values. Given this, we don't need to
+ // save anything about the post behavior, after finalizing it
+
+ // We need to tell the keyboard if the layer has been changed, either by a keyboard rule itself,
+ // or by the touch layout 'nextlayer' control.
+ this.keyboardProcessor.layerChangedStore.set(startingLayerId == this.keyboardProcessor.layerId ? '0' : '1');
+
+ let postRuleBehavior = this.keyboardProcessor.processPostKeystroke(keyEvent.device, outputTarget);
+ if(postRuleBehavior) {
+ postRuleBehavior.finalize(this.keyboardProcessor, outputTarget);
+ }
}
return ruleBehavior;
@@ -245,6 +280,12 @@ namespace com.keyman.text {
public resetContext(outputTarget?: OutputTarget) {
this.keyboardProcessor.resetContext();
this.languageProcessor.invalidateContext(outputTarget);
+
+ // Let the keyboard do its initial group processing
+ //console.log('processNewContextEvent called from resetContext');
+ if(outputTarget) {
+ this.processNewContextEvent(outputTarget);
+ }
}
}
}
diff --git a/common/core/web/input-processor/src/text/prediction/languageProcessor.ts b/common/core/web/input-processor/src/text/prediction/languageProcessor.ts
index d9a74b3a87..66c326a7a8 100644
--- a/common/core/web/input-processor/src/text/prediction/languageProcessor.ts
+++ b/common/core/web/input-processor/src/text/prediction/languageProcessor.ts
@@ -24,7 +24,7 @@ namespace com.keyman.text.prediction {
path: string;
/**
- * The raw JS script defining the model. Only used if `path` is not specified.
+ * The raw JS script defining the model. Only used if `path` is not specified.
*/
code: string;
}
@@ -123,10 +123,10 @@ namespace com.keyman.text.prediction {
lp.emit('statechange', 'active');
}
- return this.lmEngine.loadModel(source, specType).then(function(config: Configuration) {
+ return this.lmEngine.loadModel(source, specType).then(function(config: Configuration) {
lp.configuration = config;
lp.emit('statechange', 'configured');
- }).catch(function(error) {
+ }).catch(function(error) {
// Does this provide enough logging information?
let message: string;
if(error instanceof Error) {
@@ -185,7 +185,7 @@ namespace com.keyman.text.prediction {
if(!this.currentModel || !this.configuration) {
return null;
}
-
+
// We've already invalidated any suggestions resulting from any previously-existing Promise -
// may as well officially invalidate them via event.
this.emit("invalidatesuggestions", 'new');
@@ -197,7 +197,7 @@ namespace com.keyman.text.prediction {
if(!outputTarget) {
throw "Accepting suggestions requires a destination OutputTarget instance."
}
-
+
// Find the state of the context at the time the suggestion was generated.
// This may refer to the context before an input keystroke or before application
// of a predictive suggestion.
@@ -218,6 +218,10 @@ namespace com.keyman.text.prediction {
let transform = final.buildTransformFrom(outputTarget);
outputTarget.apply(transform);
+ // Tell the banner that a suggestion was applied, so it can call the
+ // keyboard's PostKeystroke entry point as needed
+ this.emit('suggestionapplied', outputTarget);
+
// Build a 'reversion' Transcription that can be used to undo this apply() if needed,
// replacing the suggestion transform with the original input text.
let preApply = text.Mock.from(original.preInput);
@@ -259,7 +263,7 @@ namespace com.keyman.text.prediction {
if(!outputTarget) {
throw "Accepting suggestions requires a destination OutputTarget instance."
}
-
+
// Find the state of the context at the time the suggestion was generated.
// This may refer to the context before an input keystroke or before application
// of a predictive suggestion.
@@ -271,7 +275,7 @@ namespace com.keyman.text.prediction {
console.warn("Could not apply the Suggestion!");
return;
}
-
+
// Apply the Reversion!
// Step 1: determine the final output text
@@ -355,7 +359,7 @@ namespace com.keyman.text.prediction {
}
/**
- * Retrieves the context and output state of KMW immediately before the prediction with
+ * Retrieves the context and output state of KMW immediately before the prediction with
* token `id` was generated. Must correspond to a 'recent' one, as only so many are stored
* in `ModelManager`'s history buffer.
* @param id A unique identifier corresponding to a recent `Transcription`.
diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json
index 9c32a3ca22..7cc3371031 100644
--- a/common/core/web/keyboard-processor/package-lock.json
+++ b/common/core/web/keyboard-processor/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/keyboard-processor",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json
index 51238fbcc7..aa3f1b8769 100644
--- a/common/core/web/keyboard-processor/package.json
+++ b/common/core/web/keyboard-processor/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/keyboard-processor",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Core module for Keyman keyboard support in KeymanWeb.",
"repository": {
"type": "git",
@@ -18,7 +18,7 @@
},
"homepage": "https://github.com/keymanapp/keyman#readme",
"devDependencies": {
- "@keymanapp/resources-gosh": "^15.0.177",
+ "@keymanapp/resources-gosh": "^15.0.184",
"chai": "^4.3.4",
"mocha": "^8.4.0",
"mocha-teamcity-reporter": "^4.0.0",
@@ -32,9 +32,9 @@
"mocha": "mocha"
},
"dependencies": {
- "@keymanapp/models-types": "^15.0.177",
- "@keymanapp/web-environment": "^15.0.177",
- "@keymanapp/web-utils": "^15.0.177",
+ "@keymanapp/models-types": "^15.0.184",
+ "@keymanapp/web-environment": "^15.0.184",
+ "@keymanapp/web-utils": "^15.0.184",
"@types/node": "^11.9.4"
}
}
diff --git a/common/core/web/keyboard-processor/src/keyboards/activeLayout.ts b/common/core/web/keyboard-processor/src/keyboards/activeLayout.ts
index 4eea4b5fd6..ac9647cdd3 100644
--- a/common/core/web/keyboard-processor/src/keyboards/activeLayout.ts
+++ b/common/core/web/keyboard-processor/src/keyboards/activeLayout.ts
@@ -158,13 +158,12 @@ namespace com.keyman.keyboards {
// Start: mirrors _GetKeyEventProperties
- // Override key shift state if specified for key in layout (corrected for popup keys KMEW-93)
- let keyShiftState = text.KeyboardProcessor.getModifierState(layer);
// First check the virtual key, and process shift, control, alt or function keys
var Lkc: text.KeyEvent = {
- Lmodifiers: keyShiftState,
- Lstates: 0,
+ // Override key shift state if specified for key in layout (corrected for popup keys KMEW-93)
+ Lmodifiers: text.KeyboardProcessor.getModifierState(layer),
+ Lstates: text.KeyboardProcessor.getStateFromLayer(layer),
Lcode: keyName ? text.Codes.keyCodes[keyName] : 0,
LisVirtualKey: true,
vkCode: 0,
diff --git a/common/core/web/keyboard-processor/src/keyboards/keyboard.ts b/common/core/web/keyboard-processor/src/keyboards/keyboard.ts
index 857d2c223d..d5d18593b0 100644
--- a/common/core/web/keyboard-processor/src/keyboards/keyboard.ts
+++ b/common/core/web/keyboard-processor/src/keyboards/keyboard.ts
@@ -58,12 +58,26 @@ namespace com.keyman.keyboards {
}
/**
- * Calls the keyboard's `gs` function, which represents the keyboard source's group(main).
+ * Calls the keyboard's `gs` function, which represents the keyboard source's begin Unicode group.
*/
process(outputTarget: text.OutputTarget, keystroke: text.KeyEvent): boolean {
return this.scriptObject['gs'](outputTarget, keystroke);
}
+ /**
+ * Calls the keyboard's `gn` function, which represents the keyboard source's begin newContext group.
+ */
+ processNewContextEvent(outputTarget: text.OutputTarget, keystroke: text.KeyEvent): boolean {
+ return this.scriptObject['gn'] ? this.scriptObject['gn'](outputTarget, keystroke) : false;
+ }
+
+ /**
+ * Calls the keyboard's `gpk` function, which represents the keyboard source's begin postKeystroke group.
+ */
+ processPostKeystroke(outputTarget: text.OutputTarget, keystroke: text.KeyEvent): boolean {
+ return this.scriptObject['gpk'] ? this.scriptObject['gpk'](outputTarget, keystroke) : false;
+ }
+
get isHollow(): boolean {
return this.scriptObject == Keyboard.DEFAULT_SCRIPT_OBJECT;
}
diff --git a/common/core/web/keyboard-processor/src/text/kbdInterface.ts b/common/core/web/keyboard-processor/src/text/kbdInterface.ts
index fb729c0468..eb190c371d 100644
--- a/common/core/web/keyboard-processor/src/text/kbdInterface.ts
+++ b/common/core/web/keyboard-processor/src/text/kbdInterface.ts
@@ -185,6 +185,7 @@ namespace com.keyman.text {
static readonly TSS_LAYER: number = 33;
static readonly TSS_PLATFORM: number = 31;
+ static readonly TSS_LAYERCHANGED: number = 42;
systemStores: {[storeID: number]: SystemStore};
@@ -201,6 +202,7 @@ namespace com.keyman.text {
this.systemStores[KeyboardInterface.TSS_PLATFORM] = new PlatformSystemStore(this);
this.systemStores[KeyboardInterface.TSS_LAYER] = new MutableSystemStore(KeyboardInterface.TSS_LAYER, 'default');
+ this.systemStores[KeyboardInterface.TSS_LAYERCHANGED] = new MutableSystemStore(KeyboardInterface.TSS_LAYERCHANGED, '0');
this.variableStoreSerializer = variableStoreSerializer;
}
@@ -948,20 +950,59 @@ namespace com.keyman.text {
this.output(1, outputTarget, "");
}
+ /**
+ * Function processNewContextEvent
+ * Scope Private
+ * @param {Object} outputTarget The target receiving input
+ * @param {Object} keystroke The input keystroke (with its properties) to be mapped by the keyboard.
+ * Description Calls the keyboard's `begin newContext` group
+ * @returns {RuleBehavior} Record of commands and state changes that result from executing `begin NewContext`
+ */
+ processNewContextEvent(outputTarget: OutputTarget, keystroke: KeyEvent): RuleBehavior {
+ if(!this.activeKeyboard) {
+ throw "No active keyboard for keystroke processing!";
+ }
+ return this.process(this.activeKeyboard.processNewContextEvent.bind(this.activeKeyboard), outputTarget, keystroke);
+ }
+
+ /**
+ * Function processPostKeystroke
+ * Scope Private
+ * @param {Object} outputTarget The target receiving input
+ * @param {Object} keystroke The input keystroke with relevant properties to be mapped by the keyboard.
+ * Description Calls the keyboard's `begin postKeystroke` group
+ * @returns {RuleBehavior} Record of commands and state changes that result from executing `begin PostKeystroke`
+ */
+ processPostKeystroke(outputTarget: OutputTarget, keystroke: KeyEvent): RuleBehavior {
+ if(!this.activeKeyboard) {
+ throw "No active keyboard for keystroke processing!";
+ }
+ return this.process(this.activeKeyboard.processPostKeystroke.bind(this.activeKeyboard), outputTarget, keystroke);
+ }
+
/**
* Function processKeystroke
* Scope Private
- * @param {Object} element The page element receiving input
+ * @param {Object} outputTarget The target receiving input
* @param {Object} keystroke The input keystroke (with its properties) to be mapped by the keyboard.
* Description Encapsulates calls to keyboard input processing.
- * @returns {number} 0 if no match is made, otherwise 1.
+ * @returns {RuleBehavior} Record of commands and state changes that result from executing `begin Unicode`
*/
processKeystroke(outputTarget: OutputTarget, keystroke: KeyEvent): RuleBehavior {
+ if(!this.activeKeyboard) {
+ throw "No active keyboard for keystroke processing!";
+ }
+ return this.process(this.activeKeyboard.process.bind(this.activeKeyboard), outputTarget, keystroke);
+ }
+
+ private process(callee, outputTarget: OutputTarget, keystroke: KeyEvent): RuleBehavior {
// Clear internal state tracking data from prior keystrokes.
if(!outputTarget) {
throw "No target specified for keyboard output!";
} else if(!this.activeKeyboard) {
throw "No active keyboard for keystroke processing!";
+ } else if(!callee) {
+ throw "No callee for keystroke processing!";
}
outputTarget.invalidateSelection();
@@ -984,7 +1025,7 @@ namespace com.keyman.text {
// Calls the start-group of the active keyboard.
this.activeTargetOutput = outputTarget;
- var matched = this.activeKeyboard.process(outputTarget, keystroke);
+ var matched = callee(outputTarget, keystroke);
this.activeTargetOutput = null;
// Finalize the rule's results.
diff --git a/common/core/web/keyboard-processor/src/text/keyEvent.ts b/common/core/web/keyboard-processor/src/text/keyEvent.ts
index 056ff66a1c..ba108f7d24 100644
--- a/common/core/web/keyboard-processor/src/text/keyEvent.ts
+++ b/common/core/web/keyboard-processor/src/text/keyEvent.ts
@@ -20,12 +20,12 @@ namespace com.keyman.text {
kLayer?: string; // The key's layer property
kbdLayer?: string; // The virtual keyboard's active layer
kNextLayer?: string;
-
+
// Holds relevant event properties leading to construction of this KeyEvent.
source?: any; // Technically, KeyEvent|MouseEvent|Touch - but those are DOM types that must be kept out of headless mode.
// Holds a generated fat-finger distribution (when appropriate)
keyDistribution?: KeyDistribution;
-
+
/**
* The device model for web-core to follow when processing the keystroke.
*/
@@ -35,5 +35,13 @@ namespace com.keyman.text {
* `true` if this event was produced by sources other than a DOM-based KeyboardEvent.
*/
isSynthetic: boolean = true;
+
+ public static constructNullKeyEvent(device: utils.DeviceSpec): KeyEvent {
+ const keyEvent = new KeyEvent();
+ keyEvent.Lcode = 0;
+ keyEvent.kName = '';
+ keyEvent.device = device;
+ return keyEvent;
+ }
};
}
\ No newline at end of file
diff --git a/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts b/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts
index f419d33716..778bcab724 100644
--- a/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts
+++ b/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts
@@ -91,6 +91,10 @@ namespace com.keyman.text {
return this.keyboardInterface.systemStores[KeyboardInterface.TSS_LAYER] as MutableSystemStore;
}
+ public get layerChangedStore(): MutableSystemStore {
+ return this.keyboardInterface.systemStores[KeyboardInterface.TSS_LAYERCHANGED] as MutableSystemStore;
+ }
+
public get layerId(): string {
return this.layerStore.value;
}
@@ -207,6 +211,24 @@ namespace com.keyman.text {
}
}
+ constructNullKeyEvent(device: utils.DeviceSpec): KeyEvent {
+ const keyEvent = KeyEvent.constructNullKeyEvent(device);
+ this.setSyntheticEventDefaults(keyEvent);
+ return keyEvent;
+ }
+
+ processNewContextEvent(device: utils.DeviceSpec, outputTarget: OutputTarget): RuleBehavior {
+ return this.activeKeyboard ?
+ this.keyboardInterface.processNewContextEvent(outputTarget, this.constructNullKeyEvent(device)) :
+ null;
+ }
+
+ processPostKeystroke(device: utils.DeviceSpec, outputTarget: OutputTarget): RuleBehavior {
+ return this.activeKeyboard ?
+ this.keyboardInterface.processPostKeystroke(outputTarget, this.constructNullKeyEvent(device)) :
+ null;
+ }
+
processKeystroke(keyEvent: KeyEvent, outputTarget: OutputTarget): RuleBehavior {
var matchBehavior: RuleBehavior;
@@ -342,6 +364,22 @@ namespace com.keyman.text {
return modifier;
}
+ /**
+ * Get state key state from layer id
+ *
+ * @param {string} layerId layer id (e.g. caps)
+ * @return {number} modifier key state (desktop keyboards)
+ */
+ static getStateFromLayer(layerId: string): number {
+ var modifier=0;
+
+ if(layerId.indexOf('caps') >= 0) {
+ modifier |= Codes.modifierCodes['CAPS'];
+ }
+
+ return modifier;
+ }
+
/**
* @summary Look up a custom virtual key code in the virtual key code dictionary KVKD. On first run, will build the dictionary.
*
diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json
index d0b22ad9c6..ba54b87737 100644
--- a/common/core/web/tools/recorder/package-lock.json
+++ b/common/core/web/tools/recorder/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/recorder-core",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json
index 338cd8024b..87f8678fe1 100644
--- a/common/core/web/tools/recorder/package.json
+++ b/common/core/web/tools/recorder/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/recorder-core",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Core classes used to develop KeymanWeb test cases based on keystrokes",
"main": "index.js",
"scripts": {
@@ -17,10 +17,10 @@
},
"homepage": "https://github.com/keymanapp/keyman#readme",
"dependencies": {
- "@keymanapp/keyboard-processor": "^15.0.177",
- "@keymanapp/models-types": "^15.0.177",
- "@keymanapp/web-environment": "^15.0.177",
- "@keymanapp/web-utils": "^15.0.177",
+ "@keymanapp/keyboard-processor": "^15.0.184",
+ "@keymanapp/models-types": "^15.0.184",
+ "@keymanapp/web-environment": "^15.0.184",
+ "@keymanapp/web-utils": "^15.0.184",
"@types/node": "^11.9.4"
},
"devDependencies": {
diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json
index e6ba9ee666..7abc5163c7 100644
--- a/common/core/web/tools/sentry-manager/package-lock.json
+++ b/common/core/web/tools/sentry-manager/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-sentry-manager",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json
index d9b757e645..1966103d54 100644
--- a/common/core/web/tools/sentry-manager/package.json
+++ b/common/core/web/tools/sentry-manager/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-sentry-manager",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Common setup for KeymanWeb's Sentry-based error reporting",
"main": "dist/index.js",
"scripts": {
@@ -20,7 +20,7 @@
"typescript": "^3.8.3"
},
"dependencies": {
- "@keymanapp/web-environment": "^15.0.177",
+ "@keymanapp/web-environment": "^15.0.184",
"@sentry/browser": "^5.27.4"
}
}
diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json
index 6e8d96f0d3..6bccd10ffb 100644
--- a/common/core/web/utils/package-lock.json
+++ b/common/core/web/utils/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-utils",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json
index fe488c9b35..519a286569 100644
--- a/common/core/web/utils/package.json
+++ b/common/core/web/utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-utils",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Common utility functions used throughout other Keyman packages",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -20,8 +20,8 @@
},
"homepage": "https://github.com/keymanapp/keyman#readme",
"devDependencies": {
- "@keymanapp/resources-gosh": "^15.0.177",
- "@keymanapp/web-environment": "^15.0.177",
+ "@keymanapp/resources-gosh": "^15.0.184",
+ "@keymanapp/web-environment": "^15.0.184",
"@types/node": "^14.0.5",
"typescript": "^3.8.3"
}
diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json
index fb3b0bd768..d29b2cc893 100644
--- a/common/models/templates/package-lock.json
+++ b/common/models/templates/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-templates",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/common/models/templates/package.json b/common/models/templates/package.json
index ed1ffa10ae..a6650885d4 100644
--- a/common/models/templates/package.json
+++ b/common/models/templates/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-templates",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Backing model implementations (templates) for Keyman's modelling layer",
"keywords": [
"lm",
@@ -42,8 +42,8 @@
"url": "https://github.com/keymanapp/keyman/issues"
},
"devDependencies": {
- "@keymanapp/models-types": "^15.0.177",
- "@keymanapp/web-utils": "^15.0.177",
+ "@keymanapp/models-types": "^15.0.184",
+ "@keymanapp/web-utils": "^15.0.184",
"@types/chai": "^4.2.11",
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.4",
@@ -52,6 +52,6 @@
"typescript": "^3.8.3"
},
"dependencies": {
- "@keymanapp/models-wordbreakers": "^15.0.177"
+ "@keymanapp/models-wordbreakers": "^15.0.184"
}
}
diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json
index ae90a7c853..5ba0c9c88e 100644
--- a/common/models/types/package-lock.json
+++ b/common/models/types/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-types",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/common/models/types/package.json b/common/models/types/package.json
index d064d52402..ee9c855eb9 100644
--- a/common/models/types/package.json
+++ b/common/models/types/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-types",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.",
"types": "./index.d.ts",
"scripts": {
diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json
index 799b6c893d..240f59f295 100644
--- a/common/models/wordbreakers/package-lock.json
+++ b/common/models/wordbreakers/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-wordbreakers",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json
index c3259055a9..6a35187b07 100644
--- a/common/models/wordbreakers/package.json
+++ b/common/models/wordbreakers/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-wordbreakers",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Word breakers bundled in the modeling layer",
"keywords": [
"lexical model",
@@ -40,7 +40,7 @@
"url": "https://github.com/keymanapp/keyman/issues"
},
"devDependencies": {
- "@keymanapp/models-types": "^15.0.177",
+ "@keymanapp/models-types": "^15.0.184",
"@types/chai": "^4.2.11",
"@types/mocha": "^7.0.2",
"chai": "^4.3.4",
diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json
index 1ccb7dfb09..bc79c375d1 100644
--- a/common/predictive-text/package-lock.json
+++ b/common/predictive-text/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/lexical-model-layer",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json
index 8bd5aef3e6..cae6e44851 100644
--- a/common/predictive-text/package.json
+++ b/common/predictive-text/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/lexical-model-layer",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Keyman/Predictive Text integration layer",
"main": "build/index.js",
"scripts": {
@@ -21,8 +21,8 @@
},
"homepage": "https://github.com/keymanapp/keyman#readme",
"devDependencies": {
- "@keymanapp/models-types": "^15.0.177",
- "@keymanapp/resources-gosh": "^15.0.177",
+ "@keymanapp/models-types": "^15.0.184",
+ "@keymanapp/resources-gosh": "^15.0.184",
"@types/node": "^10.17.21",
"chai": "^4.3.4",
"karma": "^6.3.4",
@@ -46,10 +46,10 @@
"typescript": "^3.8.3"
},
"dependencies": {
- "@keymanapp/models-templates": "^15.0.177",
- "@keymanapp/models-wordbreakers": "^15.0.177",
- "@keymanapp/web-environment": "^15.0.177",
- "@keymanapp/web-utils": "^15.0.177",
+ "@keymanapp/models-templates": "^15.0.184",
+ "@keymanapp/models-wordbreakers": "^15.0.184",
+ "@keymanapp/web-environment": "^15.0.184",
+ "@keymanapp/web-utils": "^15.0.184",
"es6-shim": "^0.35.5",
"string.prototype.codepointat": "^0.2.1",
"string.prototype.startswith": "^0.2.0"
diff --git a/common/test/keyboards/caps_lock_layer_3620/HISTORY.md b/common/test/keyboards/caps_lock_layer_3620/HISTORY.md
new file mode 100644
index 0000000000..6d9ff83606
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/HISTORY.md
@@ -0,0 +1,6 @@
+Caps Lock Layer 3620 Change History
+====================
+
+1.0 (2021-11-30)
+----------------
+* Created by
diff --git a/common/test/keyboards/caps_lock_layer_3620/LICENSE.md b/common/test/keyboards/caps_lock_layer_3620/LICENSE.md
new file mode 100644
index 0000000000..77a9531492
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+© 2021
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/common/test/keyboards/caps_lock_layer_3620/README.md b/common/test/keyboards/caps_lock_layer_3620/README.md
new file mode 100644
index 0000000000..41b2e74135
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/README.md
@@ -0,0 +1,30 @@
+Caps Lock Layer 3620 keyboard
+==============
+
+Version 1.0
+
+Description
+-----------
+Caps Lock Layer 3620 generated from template
+
+Links
+-----
+
+Copyright
+---------
+See [LICENSE.md](LICENSE.md)
+
+Supported Platforms
+-------------------
+ * Windows
+ * macOS
+ * Linux
+ * Web
+ * iPhone
+ * iPad
+ * Android phone
+ * Android tablet
+ * Mobile devices
+ * Desktop devices
+ * Tablet devices
+
diff --git a/common/test/keyboards/caps_lock_layer_3620/caps_lock_layer_3620.keyboard_info b/common/test/keyboards/caps_lock_layer_3620/caps_lock_layer_3620.keyboard_info
new file mode 100644
index 0000000000..7cabc2dfde
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/caps_lock_layer_3620.keyboard_info
@@ -0,0 +1,7 @@
+{
+ "license": "mit",
+ "languages": [
+ "en"
+ ],
+ "description": "Caps Lock Layer 3620 generated from template"
+}
diff --git a/common/test/keyboards/caps_lock_layer_3620/caps_lock_layer_3620.kpj b/common/test/keyboards/caps_lock_layer_3620/caps_lock_layer_3620.kpj
new file mode 100644
index 0000000000..57877e2346
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/caps_lock_layer_3620.kpj
@@ -0,0 +1,102 @@
+
+
+
+ $PROJECTPATH\build
+ True
+ True
+ True
+ keyboard
+
+
+
+ id_ae750e073bdf1a73f961466813e93a67
+ caps_lock_layer_3620.kmn
+ source\caps_lock_layer_3620.kmn
+ 1.0
+ .kmn
+
+ Caps Lock Layer 3620
+ ©
+
+
+
+ id_8572983c5fa67dc8f3e31da0333521b5
+ caps_lock_layer_3620.kps
+ source\caps_lock_layer_3620.kps
+
+ .kps
+
+ Caps Lock Layer 3620
+ ©
+
+
+
+ id_ede98e4633e239f933cbfd1f4e1b766c
+ HISTORY.md
+ HISTORY.md
+
+ .md
+
+
+ id_53e892b8b41cc4caece1cfd5ef21d6e7
+ LICENSE.md
+ LICENSE.md
+
+ .md
+
+
+ id_0730bb7c2e8f9ea2438b52e419dd86c9
+ README.md
+ README.md
+
+ .md
+
+
+ id_fff8738ee01fad8282ccd871d1b1d7ec
+ caps_lock_layer_3620.keyboard_info
+ caps_lock_layer_3620.keyboard_info
+
+ .keyboard_info
+
+
+ id_6beb4ed096b4f0d03913a0cf0dc1c10b
+ caps_lock_layer_3620.kmx
+ source\..\build\caps_lock_layer_3620.kmx
+
+ .kmx
+ id_8572983c5fa67dc8f3e31da0333521b5
+
+
+ id_85da30900c1f778b42f47770aa7d67ae
+ caps_lock_layer_3620.js
+ source\..\build\caps_lock_layer_3620.js
+
+ .js
+ id_8572983c5fa67dc8f3e31da0333521b5
+
+
+ id_456ab3d34c321e614773101797d2a54f
+ caps_lock_layer_3620.kvk
+ source\..\build\caps_lock_layer_3620.kvk
+
+ .kvk
+ id_8572983c5fa67dc8f3e31da0333521b5
+
+
+ id_356e5d149c1e539356d72698c1e401a6
+ welcome.htm
+ source\welcome.htm
+
+ .htm
+ id_8572983c5fa67dc8f3e31da0333521b5
+
+
+ id_8da344c4cea6f467013357fe099006f5
+ readme.htm
+ source\readme.htm
+
+ .htm
+ id_8572983c5fa67dc8f3e31da0333521b5
+
+
+
diff --git a/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.keyman-touch-layout b/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.keyman-touch-layout
new file mode 100644
index 0000000000..2cb1c723b4
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.keyman-touch-layout
@@ -0,0 +1,891 @@
+{
+ "tablet": {
+ "font": "Tahoma",
+ "layer": [
+ {
+ "id": "default",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "q"
+ },
+ {
+ "id": "K_W",
+ "text": "w"
+ },
+ {
+ "id": "K_E",
+ "text": "e"
+ },
+ {
+ "id": "K_R",
+ "text": "r"
+ },
+ {
+ "id": "K_T",
+ "text": "t"
+ },
+ {
+ "id": "K_Y",
+ "text": "y"
+ },
+ {
+ "id": "K_U",
+ "text": "u"
+ },
+ {
+ "id": "K_I",
+ "text": "i"
+ },
+ {
+ "id": "K_O",
+ "text": "o"
+ },
+ {
+ "id": "K_P",
+ "text": "p"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "a",
+ "pad": 70
+ },
+ {
+ "id": "K_S",
+ "text": "s"
+ },
+ {
+ "id": "K_D",
+ "text": "d"
+ },
+ {
+ "id": "K_F",
+ "text": "f"
+ },
+ {
+ "id": "K_G",
+ "text": "g"
+ },
+ {
+ "id": "K_H",
+ "text": "h"
+ },
+ {
+ "id": "K_J",
+ "text": "j"
+ },
+ {
+ "id": "K_K",
+ "text": "k"
+ },
+ {
+ "id": "K_L",
+ "text": "l"
+ },
+ {
+ "id": "T_new_54",
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "1",
+ "nextlayer": "shift"
+ },
+ {
+ "id": "K_Z",
+ "text": "z"
+ },
+ {
+ "id": "K_X",
+ "text": "x"
+ },
+ {
+ "id": "K_C",
+ "text": "c"
+ },
+ {
+ "id": "K_V",
+ "text": "v"
+ },
+ {
+ "id": "K_B",
+ "text": "b"
+ },
+ {
+ "id": "K_N",
+ "text": "n"
+ },
+ {
+ "id": "K_M",
+ "text": "m"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "shift",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "Q"
+ },
+ {
+ "id": "K_W",
+ "text": "W"
+ },
+ {
+ "id": "K_E",
+ "text": "E"
+ },
+ {
+ "id": "K_R",
+ "text": "R"
+ },
+ {
+ "id": "K_T",
+ "text": "T"
+ },
+ {
+ "id": "K_Y",
+ "text": "Y"
+ },
+ {
+ "id": "K_U",
+ "text": "U"
+ },
+ {
+ "id": "K_I",
+ "text": "I"
+ },
+ {
+ "id": "K_O",
+ "text": "O"
+ },
+ {
+ "id": "K_P",
+ "text": "P"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "A",
+ "pad": 70
+ },
+ {
+ "id": "K_S",
+ "text": "S"
+ },
+ {
+ "id": "K_D",
+ "text": "D"
+ },
+ {
+ "id": "K_F",
+ "text": "F"
+ },
+ {
+ "id": "K_G",
+ "text": "G"
+ },
+ {
+ "id": "K_H",
+ "text": "H"
+ },
+ {
+ "id": "K_J",
+ "text": "J"
+ },
+ {
+ "id": "K_K",
+ "text": "K"
+ },
+ {
+ "id": "K_L",
+ "text": "L"
+ },
+ {
+ "id": "T_new_190",
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "2",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_Z",
+ "text": "Z"
+ },
+ {
+ "id": "K_X",
+ "text": "X"
+ },
+ {
+ "id": "K_C",
+ "text": "C"
+ },
+ {
+ "id": "K_V",
+ "text": "V"
+ },
+ {
+ "id": "K_B",
+ "text": "B"
+ },
+ {
+ "id": "K_N",
+ "text": "N"
+ },
+ {
+ "id": "K_M",
+ "text": "M"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "layer": "default",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA",
+ "layer": "default"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE",
+ "layer": "default"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH",
+ "layer": "default"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON",
+ "layer": "default"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "numeric",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_1",
+ "text": "1"
+ },
+ {
+ "id": "K_2",
+ "text": "2"
+ },
+ {
+ "id": "K_3",
+ "text": "3"
+ },
+ {
+ "id": "K_4",
+ "text": "4"
+ },
+ {
+ "id": "K_5",
+ "text": "5"
+ },
+ {
+ "id": "K_6",
+ "text": "6"
+ },
+ {
+ "id": "K_7",
+ "text": "7"
+ },
+ {
+ "id": "K_8",
+ "text": "8"
+ },
+ {
+ "id": "K_9",
+ "text": "9"
+ },
+ {
+ "id": "K_0",
+ "text": "0"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_4",
+ "text": "$",
+ "pad": 70,
+ "layer": "shift"
+ },
+ {
+ "id": "K_2",
+ "text": "@",
+ "layer": "shift"
+ },
+ {
+ "id": "K_3",
+ "text": "#",
+ "layer": "shift"
+ },
+ {
+ "id": "K_5",
+ "text": "%",
+ "layer": "shift"
+ },
+ {
+ "id": "K_7",
+ "text": "&",
+ "layer": "shift"
+ },
+ {
+ "id": "K_HYPHEN",
+ "text": "_",
+ "layer": "shift"
+ },
+ {
+ "id": "K_EQUAL",
+ "text": "=",
+ "layer": "default"
+ },
+ {
+ "id": "K_BKSLASH",
+ "text": "|",
+ "layer": "shift"
+ },
+ {
+ "id": "K_BKSLASH",
+ "text": "\\",
+ "layer": "default"
+ },
+ {
+ "id": "T_new_536",
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "1",
+ "nextlayer": "shift"
+ },
+ {
+ "id": "K_LBRKT",
+ "text": "[",
+ "sk": [
+ {
+ "id": "U_00AB",
+ "text": "«"
+ },
+ {
+ "id": "K_COMMA",
+ "text": "<",
+ "layer": "shift"
+ },
+ {
+ "id": "K_LBRKT",
+ "text": "{",
+ "layer": "shift"
+ }
+ ]
+ },
+ {
+ "id": "K_9",
+ "text": "(",
+ "layer": "shift"
+ },
+ {
+ "id": "K_0",
+ "text": ")",
+ "layer": "shift"
+ },
+ {
+ "id": "K_RBRKT",
+ "text": "]",
+ "sk": [
+ {
+ "id": "U_00BB",
+ "text": "»"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ">",
+ "layer": "shift"
+ },
+ {
+ "id": "K_RBRKT",
+ "text": "}",
+ "layer": "shift"
+ }
+ ]
+ },
+ {
+ "id": "K_EQUAL",
+ "text": "+",
+ "layer": "shift"
+ },
+ {
+ "id": "K_HYPHEN",
+ "text": "-",
+ "layer": "default"
+ },
+ {
+ "id": "K_8",
+ "text": "*",
+ "layer": "shift"
+ },
+ {
+ "id": "K_SLASH",
+ "text": "/",
+ "layer": "default"
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_LOWER",
+ "text": "*abc*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "caps",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "Q"
+ },
+ {
+ "id": "K_W",
+ "text": "W"
+ },
+ {
+ "id": "K_E",
+ "text": "E"
+ },
+ {
+ "id": "K_R",
+ "text": "R"
+ },
+ {
+ "id": "K_T",
+ "text": "T"
+ },
+ {
+ "id": "K_Y",
+ "text": "Y"
+ },
+ {
+ "id": "K_U",
+ "text": "U"
+ },
+ {
+ "id": "K_I",
+ "text": "I"
+ },
+ {
+ "id": "K_O",
+ "text": "O"
+ },
+ {
+ "id": "K_P",
+ "text": "P"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "A",
+ "pad": 70
+ },
+ {
+ "id": "K_S",
+ "text": "S"
+ },
+ {
+ "id": "K_D",
+ "text": "D"
+ },
+ {
+ "id": "K_F",
+ "text": "F"
+ },
+ {
+ "id": "K_G",
+ "text": "G"
+ },
+ {
+ "id": "K_H",
+ "text": "H"
+ },
+ {
+ "id": "K_J",
+ "text": "J"
+ },
+ {
+ "id": "K_K",
+ "text": "K"
+ },
+ {
+ "id": "K_L",
+ "text": "L"
+ },
+ {
+ "id": "T_new_190",
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*ShiftedLock*",
+ "width": "110",
+ "sp": "2",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_Z",
+ "text": "Z"
+ },
+ {
+ "id": "K_X",
+ "text": "X"
+ },
+ {
+ "id": "K_C",
+ "text": "C"
+ },
+ {
+ "id": "K_V",
+ "text": "V"
+ },
+ {
+ "id": "K_B",
+ "text": "B"
+ },
+ {
+ "id": "K_N",
+ "text": "N"
+ },
+ {
+ "id": "K_M",
+ "text": "M"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "layer": "default",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA",
+ "layer": "default"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE",
+ "layer": "default"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH",
+ "layer": "default"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON",
+ "layer": "default"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "displayUnderlying": false
+ }
+}
\ No newline at end of file
diff --git a/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kmn b/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kmn
new file mode 100644
index 0000000000..311d89db39
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kmn
@@ -0,0 +1,20 @@
+c caps_lock_layer_3620 generated from template at 2021-11-30 14:58:52
+c with name "Caps Lock Layer 3620"
+store(&VERSION) '10.0'
+store(&NAME) 'Caps Lock Layer 3620'
+store(©RIGHT) '©'
+store(&KEYBOARDVERSION) '1.0'
+store(&TARGETS) 'any'
+store(&VISUALKEYBOARD) 'caps_lock_layer_3620.kvks'
+store(&LAYOUTFILE) 'caps_lock_layer_3620.keyman-touch-layout'
+
+begin Unicode > use(main)
+
+store(key) [K_A] .. [K_Z] [SHIFT K_A] .. [SHIFT K_Z]
+store(out) 'a' .. 'z' 'A' .. 'Z'
+store(&CasedKeys) [K_A] .. [K_Z]
+
+group(main) using keys
+
++ any(key) > index(out, 1)
+
diff --git a/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kps b/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kps
new file mode 100644
index 0000000000..21b405891f
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kps
@@ -0,0 +1,67 @@
+
+
+
+ 15.0.114.0
+ 7.0
+
+
+
+ readme.htm
+
+
+
+
+
+
+
+
+
+ Caps Lock Layer 3620
+ ©
+
+
+
+
+
+ ..\build\caps_lock_layer_3620.kmx
+
+ 0
+ .kmx
+
+
+ ..\build\caps_lock_layer_3620.js
+
+ 0
+ .js
+
+
+ ..\build\caps_lock_layer_3620.kvk
+
+ 0
+ .kvk
+
+
+ welcome.htm
+
+ 0
+ .htm
+
+
+ readme.htm
+
+ 0
+ .htm
+
+
+
+
+ Caps Lock Layer 3620
+ caps_lock_layer_3620
+ 1.0
+
+ English
+
+
+
+
+
diff --git a/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kvks b/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kvks
new file mode 100644
index 0000000000..8a431bbadf
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/source/caps_lock_layer_3620.kvks
@@ -0,0 +1,8 @@
+
+
+
+ 10.0
+ caps_lock_layer_3620
+
+
+
diff --git a/common/test/keyboards/caps_lock_layer_3620/source/readme.htm b/common/test/keyboards/caps_lock_layer_3620/source/readme.htm
new file mode 100644
index 0000000000..44af0713e9
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/source/readme.htm
@@ -0,0 +1,24 @@
+
+
+
+
+
+ Caps Lock Layer 3620
+
+
+
+
+Caps Lock Layer 3620
+
+
+ Caps Lock Layer 3620 1.0 generated from template.
+
+
+©
+
+
+
diff --git a/common/test/keyboards/caps_lock_layer_3620/source/welcome.htm b/common/test/keyboards/caps_lock_layer_3620/source/welcome.htm
new file mode 100644
index 0000000000..354c6a06bd
--- /dev/null
+++ b/common/test/keyboards/caps_lock_layer_3620/source/welcome.htm
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Start Using Caps Lock Layer 3620
+
+
+
+
+Start Using Caps Lock Layer 3620
+
+
+ Caps Lock Layer 3620 1.0 generated from template.
+
+
+Keyboard Layout
+
+
+
+
+
\ No newline at end of file
diff --git a/common/test/keyboards/full_caps_3620_3621/HISTORY.md b/common/test/keyboards/full_caps_3620_3621/HISTORY.md
new file mode 100644
index 0000000000..8730b47169
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/HISTORY.md
@@ -0,0 +1,6 @@
+full_caps_3620_3621 Change History
+====================
+
+1.0 (2021-12-01)
+----------------
+* Created by
diff --git a/common/test/keyboards/full_caps_3620_3621/LICENSE.md b/common/test/keyboards/full_caps_3620_3621/LICENSE.md
new file mode 100644
index 0000000000..77a9531492
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+© 2021
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/common/test/keyboards/full_caps_3620_3621/README.md b/common/test/keyboards/full_caps_3620_3621/README.md
new file mode 100644
index 0000000000..6207e0ebc8
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/README.md
@@ -0,0 +1,30 @@
+full_caps_3620_3621 keyboard
+==============
+
+Version 1.0
+
+Description
+-----------
+full_caps_3620_3621 generated from template
+
+Links
+-----
+
+Copyright
+---------
+See [LICENSE.md](LICENSE.md)
+
+Supported Platforms
+-------------------
+ * Windows
+ * macOS
+ * Linux
+ * Web
+ * iPhone
+ * iPad
+ * Android phone
+ * Android tablet
+ * Mobile devices
+ * Desktop devices
+ * Tablet devices
+
diff --git a/common/test/keyboards/full_caps_3620_3621/full_caps_3620_3621.keyboard_info b/common/test/keyboards/full_caps_3620_3621/full_caps_3620_3621.keyboard_info
new file mode 100644
index 0000000000..3bcee18837
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/full_caps_3620_3621.keyboard_info
@@ -0,0 +1,7 @@
+{
+ "license": "mit",
+ "languages": [
+ "en"
+ ],
+ "description": "full_caps_3620_3621 generated from template"
+}
diff --git a/common/test/keyboards/full_caps_3620_3621/full_caps_3620_3621.kpj b/common/test/keyboards/full_caps_3620_3621/full_caps_3620_3621.kpj
new file mode 100644
index 0000000000..96cb56925c
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/full_caps_3620_3621.kpj
@@ -0,0 +1,102 @@
+
+
+
+ $PROJECTPATH\build
+ True
+ True
+ True
+ keyboard
+
+
+
+ id_48789b910029398efc8e93b3cf8ead67
+ full_caps_3620_3621.kmn
+ source\full_caps_3620_3621.kmn
+ 1.0
+ .kmn
+
+ full_caps_3620_3621
+ ©
+
+
+
+ id_0a20f9a938ef015f88d1e10294793d49
+ full_caps_3620_3621.kps
+ source\full_caps_3620_3621.kps
+
+ .kps
+
+ full_caps_3620_3621
+ ©
+
+
+
+ id_ede98e4633e239f933cbfd1f4e1b766c
+ HISTORY.md
+ HISTORY.md
+
+ .md
+
+
+ id_53e892b8b41cc4caece1cfd5ef21d6e7
+ LICENSE.md
+ LICENSE.md
+
+ .md
+
+
+ id_0730bb7c2e8f9ea2438b52e419dd86c9
+ README.md
+ README.md
+
+ .md
+
+
+ id_da795226173614238dd92754311e5f15
+ full_caps_3620_3621.keyboard_info
+ full_caps_3620_3621.keyboard_info
+
+ .keyboard_info
+
+
+ id_3087832d59de33f9903fc21ba620b576
+ full_caps_3620_3621.kmx
+ source\..\build\full_caps_3620_3621.kmx
+
+ .kmx
+ id_0a20f9a938ef015f88d1e10294793d49
+
+
+ id_5ac2d34b9f02b291dd03055796f14de3
+ full_caps_3620_3621.js
+ source\..\build\full_caps_3620_3621.js
+
+ .js
+ id_0a20f9a938ef015f88d1e10294793d49
+
+
+ id_74e4dcbb99594bddbe39b1fcac0ea24f
+ full_caps_3620_3621.kvk
+ source\..\build\full_caps_3620_3621.kvk
+
+ .kvk
+ id_0a20f9a938ef015f88d1e10294793d49
+
+
+ id_356e5d149c1e539356d72698c1e401a6
+ welcome.htm
+ source\welcome.htm
+
+ .htm
+ id_0a20f9a938ef015f88d1e10294793d49
+
+
+ id_8da344c4cea6f467013357fe099006f5
+ readme.htm
+ source\readme.htm
+
+ .htm
+ id_0a20f9a938ef015f88d1e10294793d49
+
+
+
diff --git a/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.keyman-touch-layout b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.keyman-touch-layout
new file mode 100644
index 0000000000..e1388dd4fc
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.keyman-touch-layout
@@ -0,0 +1,889 @@
+{
+ "tablet": {
+ "font": "Tahoma",
+ "layer": [
+ {
+ "id": "default",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "q"
+ },
+ {
+ "id": "K_W",
+ "text": "w"
+ },
+ {
+ "id": "K_E",
+ "text": "e"
+ },
+ {
+ "id": "K_R",
+ "text": "r"
+ },
+ {
+ "id": "K_T",
+ "text": "t"
+ },
+ {
+ "id": "K_Y",
+ "text": "y"
+ },
+ {
+ "id": "K_U",
+ "text": "u"
+ },
+ {
+ "id": "K_I",
+ "text": "i"
+ },
+ {
+ "id": "K_O",
+ "text": "o"
+ },
+ {
+ "id": "K_P",
+ "text": "p"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "a",
+ "pad": 70
+ },
+ {
+ "id": "K_S",
+ "text": "s"
+ },
+ {
+ "id": "K_D",
+ "text": "d"
+ },
+ {
+ "id": "K_F",
+ "text": "f"
+ },
+ {
+ "id": "K_G",
+ "text": "g"
+ },
+ {
+ "id": "K_H",
+ "text": "h"
+ },
+ {
+ "id": "K_J",
+ "text": "j"
+ },
+ {
+ "id": "K_K",
+ "text": "k"
+ },
+ {
+ "id": "K_L",
+ "text": "l"
+ },
+ {
+ "id": "T_new_54",
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "1",
+ "nextlayer": "shift"
+ },
+ {
+ "id": "K_Z",
+ "text": "z"
+ },
+ {
+ "id": "K_X",
+ "text": "x"
+ },
+ {
+ "id": "K_C",
+ "text": "c"
+ },
+ {
+ "id": "K_V",
+ "text": "v"
+ },
+ {
+ "id": "K_B",
+ "text": "b"
+ },
+ {
+ "id": "K_N",
+ "text": "n"
+ },
+ {
+ "id": "K_M",
+ "text": "m"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "shift",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "Q"
+ },
+ {
+ "id": "K_W",
+ "text": "W"
+ },
+ {
+ "id": "K_E",
+ "text": "E"
+ },
+ {
+ "id": "K_R",
+ "text": "R"
+ },
+ {
+ "id": "K_T",
+ "text": "T"
+ },
+ {
+ "id": "K_Y",
+ "text": "Y"
+ },
+ {
+ "id": "K_U",
+ "text": "U"
+ },
+ {
+ "id": "K_I",
+ "text": "I"
+ },
+ {
+ "id": "K_O",
+ "text": "O"
+ },
+ {
+ "id": "K_P",
+ "text": "P"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "A",
+ "pad": 70
+ },
+ {
+ "id": "K_S",
+ "text": "S"
+ },
+ {
+ "id": "K_D",
+ "text": "D"
+ },
+ {
+ "id": "K_F",
+ "text": "F"
+ },
+ {
+ "id": "K_G",
+ "text": "G"
+ },
+ {
+ "id": "K_H",
+ "text": "H"
+ },
+ {
+ "id": "K_J",
+ "text": "J"
+ },
+ {
+ "id": "K_K",
+ "text": "K"
+ },
+ {
+ "id": "K_L",
+ "text": "L"
+ },
+ {
+ "id": "T_new_88",
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "2",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_Z",
+ "text": "Z"
+ },
+ {
+ "id": "K_X",
+ "text": "X"
+ },
+ {
+ "id": "K_C",
+ "text": "C"
+ },
+ {
+ "id": "K_V",
+ "text": "V"
+ },
+ {
+ "id": "K_B",
+ "text": "B"
+ },
+ {
+ "id": "K_N",
+ "text": "N"
+ },
+ {
+ "id": "K_M",
+ "text": "M"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "layer": "default",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA",
+ "layer": "default"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE",
+ "layer": "default"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH",
+ "layer": "default"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON",
+ "layer": "default"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "numeric",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_1",
+ "text": "1"
+ },
+ {
+ "id": "K_2",
+ "text": "2"
+ },
+ {
+ "id": "K_3",
+ "text": "3"
+ },
+ {
+ "id": "K_4",
+ "text": "4"
+ },
+ {
+ "id": "K_5",
+ "text": "5"
+ },
+ {
+ "id": "K_6",
+ "text": "6"
+ },
+ {
+ "id": "K_7",
+ "text": "7"
+ },
+ {
+ "id": "K_8",
+ "text": "8"
+ },
+ {
+ "id": "K_9",
+ "text": "9"
+ },
+ {
+ "id": "K_0",
+ "text": "0"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_4",
+ "text": "$",
+ "layer": "shift",
+ "pad": 70
+ },
+ {
+ "id": "K_2",
+ "text": "@",
+ "layer": "shift"
+ },
+ {
+ "id": "K_3",
+ "text": "#",
+ "layer": "shift"
+ },
+ {
+ "id": "K_5",
+ "text": "%",
+ "layer": "shift"
+ },
+ {
+ "id": "K_7",
+ "text": "&",
+ "layer": "shift"
+ },
+ {
+ "id": "K_HYPHEN",
+ "text": "_",
+ "layer": "shift"
+ },
+ {
+ "id": "K_EQUAL",
+ "text": "=",
+ "layer": "default"
+ },
+ {
+ "id": "K_BKSLASH",
+ "text": "|",
+ "layer": "shift"
+ },
+ {
+ "id": "K_BKSLASH",
+ "text": "\\",
+ "layer": "default"
+ },
+ {
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "1"
+ },
+ {
+ "id": "K_LBRKT",
+ "text": "[",
+ "sk": [
+ {
+ "id": "U_00AB",
+ "text": "«"
+ },
+ {
+ "id": "K_COMMA",
+ "text": "<",
+ "layer": "shift"
+ },
+ {
+ "id": "K_LBRKT",
+ "text": "{",
+ "layer": "shift"
+ }
+ ]
+ },
+ {
+ "id": "K_9",
+ "text": "(",
+ "layer": "shift"
+ },
+ {
+ "id": "K_0",
+ "text": ")",
+ "layer": "shift"
+ },
+ {
+ "id": "K_RBRKT",
+ "text": "]",
+ "sk": [
+ {
+ "id": "U_00BB",
+ "text": "»"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ">",
+ "layer": "shift"
+ },
+ {
+ "id": "K_RBRKT",
+ "text": "}",
+ "layer": "shift"
+ }
+ ]
+ },
+ {
+ "id": "K_EQUAL",
+ "text": "+",
+ "layer": "shift"
+ },
+ {
+ "id": "K_HYPHEN",
+ "text": "-",
+ "layer": "default"
+ },
+ {
+ "id": "K_8",
+ "text": "*",
+ "layer": "shift"
+ },
+ {
+ "id": "K_SLASH",
+ "text": "/",
+ "layer": "default"
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_LOWER",
+ "text": "*abc*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "caps",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "Q"
+ },
+ {
+ "id": "K_W",
+ "text": "W"
+ },
+ {
+ "id": "K_E",
+ "text": "E"
+ },
+ {
+ "id": "K_R",
+ "text": "R"
+ },
+ {
+ "id": "K_T",
+ "text": "T"
+ },
+ {
+ "id": "K_Y",
+ "text": "Y"
+ },
+ {
+ "id": "K_U",
+ "text": "U"
+ },
+ {
+ "id": "K_I",
+ "text": "I"
+ },
+ {
+ "id": "K_O",
+ "text": "O"
+ },
+ {
+ "id": "K_P",
+ "text": "P"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "A",
+ "pad": 70
+ },
+ {
+ "id": "K_S",
+ "text": "S"
+ },
+ {
+ "id": "K_D",
+ "text": "D"
+ },
+ {
+ "id": "K_F",
+ "text": "F"
+ },
+ {
+ "id": "K_G",
+ "text": "G"
+ },
+ {
+ "id": "K_H",
+ "text": "H"
+ },
+ {
+ "id": "K_J",
+ "text": "J"
+ },
+ {
+ "id": "K_K",
+ "text": "K"
+ },
+ {
+ "id": "K_L",
+ "text": "L"
+ },
+ {
+ "id": "T_new_88",
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*ShiftedLock*",
+ "width": "110",
+ "sp": "2",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_Z",
+ "text": "Z"
+ },
+ {
+ "id": "K_X",
+ "text": "X"
+ },
+ {
+ "id": "K_C",
+ "text": "C"
+ },
+ {
+ "id": "K_V",
+ "text": "V"
+ },
+ {
+ "id": "K_B",
+ "text": "B"
+ },
+ {
+ "id": "K_N",
+ "text": "N"
+ },
+ {
+ "id": "K_M",
+ "text": "M"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "layer": "default",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA",
+ "layer": "default"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE",
+ "layer": "default"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH",
+ "layer": "default"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON",
+ "layer": "default"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "displayUnderlying": false
+ }
+}
\ No newline at end of file
diff --git a/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kmn b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kmn
new file mode 100644
index 0000000000..aa7c9aa40a
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kmn
@@ -0,0 +1,56 @@
+c full_caps_3620_3621 generated from template at 2021-12-01 08:45:15
+c with name "full_caps_3620_3621"
+store(&VERSION) '10.0'
+store(&NAME) 'full_caps_3620_3621'
+store(©RIGHT) '©'
+store(&KEYBOARDVERSION) '1.0'
+store(&TARGETS) 'any'
+store(&VISUALKEYBOARD) 'full_caps_3620_3621.kvks'
+store(&LAYOUTFILE) 'full_caps_3620_3621.keyman-touch-layout'
+
+begin Unicode > use(main)
+begin NewContext > use(NewContext)
+begin PostKeystroke > use(PostKeystroke)
+
+store(key) [K_A] .. [K_Z] [SHIFT K_A] .. [SHIFT K_Z]
+store(out) 'a' .. 'z' 'A' .. 'Z'
+store(&CasedKeys) [K_A] .. [K_Z]
+store(caps) 'A'..'Z'
+store(digit) '0'..'9'
+
+group(NewContext) readonly
+ c Any time we get a new context, by mouse click, tap,
+ c cursor movement, new document, etc, we'll try and
+ c determine the best layer to use
+ nomatch > use(nextLayer)
+
+group(PostKeystroke) readonly
+ c this is a heuristic: if we find two+ characters in capitals, leave
+ c us in shift layer, assuming the user hasn't just switched layer
+ c themselves. Not sure if this is a good idea!
+ c if(&layerChanged = "0") if(&layer = 'shift') any(caps) any(caps) > layer('caps') c ??? is this a good idea?
+
+ c stay on the numeric layer if we are there already
+ if(&layerChanged = "0") if(&layer = 'numeric') any(digit) > context
+
+ c don't cancel caps lock layer
+ if(&layer = 'caps') > context
+
+ c no other changes, so detect sentence or layer change, as long
+ c as the user hasn't attempted to change layer themselves
+ if(&layerChanged = "0") > use(nextLayer)
+
+group(nextLayer) readonly
+ store(sentencePunctuation) '.?!'
+ nul > layer('shift')
+ c note that 'readonly' layers do not need to use 'context' unless there is
+ c no other content on output of rule (empty output is illegal)
+ any(sentencePunctuation) ' ' > layer('shift')
+ any(sentencePunctuation) ' ' > layer('shift')
+ nomatch > layer('default')
+
+group(main) using keys
+
+ + any(key) > index(out, 1)
+
+
diff --git a/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kps b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kps
new file mode 100644
index 0000000000..82a731ca44
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kps
@@ -0,0 +1,67 @@
+
+
+
+ 15.0.114.0
+ 7.0
+
+
+
+ readme.htm
+
+
+
+
+
+
+
+
+
+ full_caps_3620_3621
+ ©
+
+
+
+
+
+ ..\build\full_caps_3620_3621.kmx
+
+ 0
+ .kmx
+
+
+ ..\build\full_caps_3620_3621.js
+
+ 0
+ .js
+
+
+ ..\build\full_caps_3620_3621.kvk
+
+ 0
+ .kvk
+
+
+ welcome.htm
+
+ 0
+ .htm
+
+
+ readme.htm
+
+ 0
+ .htm
+
+
+
+
+ full_caps_3620_3621
+ full_caps_3620_3621
+ 1.0
+
+ English
+
+
+
+
+
diff --git a/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kvks b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kvks
new file mode 100644
index 0000000000..ea1a6c0bb0
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kvks
@@ -0,0 +1,110 @@
+
+
+
+ 10.0
+ full_caps_3620_3621
+
+
+
+
+ `
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 0
+ -
+ =
+ q
+ w
+ e
+ r
+ t
+ y
+ u
+ i
+ o
+ p
+ [
+ ]
+ \
+ a
+ s
+ d
+ f
+ g
+ h
+ j
+ k
+ l
+ ;
+ '
+ \
+ z
+ x
+ c
+ v
+ b
+ n
+ m
+ ,
+ .
+ /
+
+
+ ~
+ !
+ @
+ #
+ $
+ %
+ ^
+ &
+ *
+ (
+ )
+ _
+ +
+ Q
+ W
+ E
+ R
+ T
+ Y
+ U
+ I
+ O
+ P
+ {
+ }
+ |
+ A
+ S
+ D
+ F
+ G
+ H
+ J
+ K
+ L
+ :
+ "
+ |
+ Z
+ X
+ C
+ V
+ B
+ N
+ M
+ <
+ >
+ ?
+
+
+
diff --git a/common/test/keyboards/full_caps_3620_3621/source/readme.htm b/common/test/keyboards/full_caps_3620_3621/source/readme.htm
new file mode 100644
index 0000000000..bee5b5959e
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/source/readme.htm
@@ -0,0 +1,24 @@
+
+
+
+
+
+ full_caps_3620_3621
+
+
+
+
+full_caps_3620_3621
+
+
+ full_caps_3620_3621 1.0 generated from template.
+
+
+©
+
+
+
diff --git a/common/test/keyboards/full_caps_3620_3621/source/welcome.htm b/common/test/keyboards/full_caps_3620_3621/source/welcome.htm
new file mode 100644
index 0000000000..3d6d025c4c
--- /dev/null
+++ b/common/test/keyboards/full_caps_3620_3621/source/welcome.htm
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Start Using full_caps_3620_3621
+
+
+
+
+Start Using full_caps_3620_3621
+
+
+ full_caps_3620_3621 1.0 generated from template.
+
+
+Keyboard Layout
+
+
+
+
+
\ No newline at end of file
diff --git a/common/test/keyboards/start_of_sentence_3621/.gitignore b/common/test/keyboards/start_of_sentence_3621/.gitignore
new file mode 100644
index 0000000000..d16386367f
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/.gitignore
@@ -0,0 +1 @@
+build/
\ No newline at end of file
diff --git a/common/test/keyboards/start_of_sentence_3621/HISTORY.md b/common/test/keyboards/start_of_sentence_3621/HISTORY.md
new file mode 100644
index 0000000000..5f3230a787
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/HISTORY.md
@@ -0,0 +1,6 @@
+start_of_sentence_3621 Change History
+====================
+
+1.0 (2021-11-22)
+----------------
+* Created by
diff --git a/common/test/keyboards/start_of_sentence_3621/LICENSE.md b/common/test/keyboards/start_of_sentence_3621/LICENSE.md
new file mode 100644
index 0000000000..77a9531492
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+© 2021
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/common/test/keyboards/start_of_sentence_3621/README.md b/common/test/keyboards/start_of_sentence_3621/README.md
new file mode 100644
index 0000000000..29041c3083
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/README.md
@@ -0,0 +1,30 @@
+start_of_sentence_3621 keyboard
+==============
+
+Version 1.0
+
+Description
+-----------
+start_of_sentence_3621 generated from template
+
+Links
+-----
+
+Copyright
+---------
+See [LICENSE.md](LICENSE.md)
+
+Supported Platforms
+-------------------
+ * Windows
+ * macOS
+ * Linux
+ * Web
+ * iPhone
+ * iPad
+ * Android phone
+ * Android tablet
+ * Mobile devices
+ * Desktop devices
+ * Tablet devices
+
diff --git a/common/test/keyboards/start_of_sentence_3621/source/readme.htm b/common/test/keyboards/start_of_sentence_3621/source/readme.htm
new file mode 100644
index 0000000000..c8b434197f
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/source/readme.htm
@@ -0,0 +1,24 @@
+
+
+
+
+
+ start_of_sentence_3621
+
+
+
+
+start_of_sentence_3621
+
+
+ start_of_sentence_3621 1.0 generated from template.
+
+
+©
+
+
+
diff --git a/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.keyman-touch-layout b/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.keyman-touch-layout
new file mode 100644
index 0000000000..bf09ed0bf9
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.keyman-touch-layout
@@ -0,0 +1,1316 @@
+{
+ "tablet": {
+ "font": "Tahoma",
+ "layer": [
+ {
+ "id": "default",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "q"
+ },
+ {
+ "id": "K_W",
+ "text": "w"
+ },
+ {
+ "id": "K_E",
+ "text": "e"
+ },
+ {
+ "id": "K_R",
+ "text": "r"
+ },
+ {
+ "id": "K_T",
+ "text": "t"
+ },
+ {
+ "id": "K_Y",
+ "text": "y"
+ },
+ {
+ "id": "K_U",
+ "text": "u"
+ },
+ {
+ "id": "K_I",
+ "text": "i"
+ },
+ {
+ "id": "K_O",
+ "text": "o"
+ },
+ {
+ "id": "K_P",
+ "text": "p"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "a",
+ "pad": 70
+ },
+ {
+ "id": "K_S",
+ "text": "s"
+ },
+ {
+ "id": "K_D",
+ "text": "d"
+ },
+ {
+ "id": "K_F",
+ "text": "f"
+ },
+ {
+ "id": "K_G",
+ "text": "g"
+ },
+ {
+ "id": "K_H",
+ "text": "h"
+ },
+ {
+ "id": "K_J",
+ "text": "j"
+ },
+ {
+ "id": "K_K",
+ "text": "k"
+ },
+ {
+ "id": "K_L",
+ "text": "l"
+ },
+ {
+ "sp": "10",
+ "width": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "1",
+ "nextlayer": "shift"
+ },
+ {
+ "id": "K_Z",
+ "text": "z"
+ },
+ {
+ "id": "K_X",
+ "text": "x"
+ },
+ {
+ "id": "K_C",
+ "text": "c"
+ },
+ {
+ "id": "K_V",
+ "text": "v"
+ },
+ {
+ "id": "K_B",
+ "text": "b"
+ },
+ {
+ "id": "K_N",
+ "text": "n"
+ },
+ {
+ "id": "K_M",
+ "text": "m"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "shift",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "Q"
+ },
+ {
+ "id": "K_W",
+ "text": "W"
+ },
+ {
+ "id": "K_E",
+ "text": "E"
+ },
+ {
+ "id": "K_R",
+ "text": "R"
+ },
+ {
+ "id": "K_T",
+ "text": "T"
+ },
+ {
+ "id": "K_Y",
+ "text": "Y"
+ },
+ {
+ "id": "K_U",
+ "text": "U"
+ },
+ {
+ "id": "K_I",
+ "text": "I"
+ },
+ {
+ "id": "K_O",
+ "text": "O"
+ },
+ {
+ "id": "K_P",
+ "text": "P"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "A",
+ "pad": 70
+ },
+ {
+ "id": "K_S",
+ "text": "S"
+ },
+ {
+ "id": "K_D",
+ "text": "D"
+ },
+ {
+ "id": "K_F",
+ "text": "F"
+ },
+ {
+ "id": "K_G",
+ "text": "G"
+ },
+ {
+ "id": "K_H",
+ "text": "H"
+ },
+ {
+ "id": "K_J",
+ "text": "J"
+ },
+ {
+ "id": "K_K",
+ "text": "K"
+ },
+ {
+ "id": "K_L",
+ "text": "L"
+ },
+ {
+ "sp": "10",
+ "width": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "2",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_Z",
+ "text": "Z"
+ },
+ {
+ "id": "K_X",
+ "text": "X"
+ },
+ {
+ "id": "K_C",
+ "text": "C"
+ },
+ {
+ "id": "K_V",
+ "text": "V"
+ },
+ {
+ "id": "K_B",
+ "text": "B"
+ },
+ {
+ "id": "K_N",
+ "text": "N"
+ },
+ {
+ "id": "K_M",
+ "text": "M"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "layer": "default",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA",
+ "layer": "default"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE",
+ "layer": "default"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH",
+ "layer": "default"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON",
+ "layer": "default"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "numeric",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_1",
+ "text": "1"
+ },
+ {
+ "id": "K_2",
+ "text": "2"
+ },
+ {
+ "id": "K_3",
+ "text": "3"
+ },
+ {
+ "id": "K_4",
+ "text": "4"
+ },
+ {
+ "id": "K_5",
+ "text": "5"
+ },
+ {
+ "id": "K_6",
+ "text": "6"
+ },
+ {
+ "id": "K_7",
+ "text": "7"
+ },
+ {
+ "id": "K_8",
+ "text": "8"
+ },
+ {
+ "id": "K_9",
+ "text": "9"
+ },
+ {
+ "id": "K_0",
+ "text": "0"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_4",
+ "text": "$",
+ "layer": "shift",
+ "pad": 70
+ },
+ {
+ "id": "K_2",
+ "text": "@",
+ "layer": "shift"
+ },
+ {
+ "id": "K_3",
+ "text": "#",
+ "layer": "shift"
+ },
+ {
+ "id": "K_5",
+ "text": "%",
+ "layer": "shift"
+ },
+ {
+ "id": "K_7",
+ "text": "&",
+ "layer": "shift"
+ },
+ {
+ "id": "K_HYPHEN",
+ "text": "_",
+ "layer": "shift"
+ },
+ {
+ "id": "K_EQUAL",
+ "text": "=",
+ "layer": "default"
+ },
+ {
+ "id": "K_BKSLASH",
+ "text": "|",
+ "layer": "shift"
+ },
+ {
+ "id": "K_BKSLASH",
+ "text": "\\",
+ "layer": "default"
+ },
+ {
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "width": "110",
+ "sp": "1"
+ },
+ {
+ "id": "K_LBRKT",
+ "text": "[",
+ "sk": [
+ {
+ "id": "U_00AB",
+ "text": "\u00AB"
+ },
+ {
+ "id": "K_COMMA",
+ "text": "<",
+ "layer": "shift"
+ },
+ {
+ "id": "K_LBRKT",
+ "text": "{",
+ "layer": "shift"
+ }
+ ]
+ },
+ {
+ "id": "K_9",
+ "text": "(",
+ "layer": "shift"
+ },
+ {
+ "id": "K_0",
+ "text": ")",
+ "layer": "shift"
+ },
+ {
+ "id": "K_RBRKT",
+ "text": "]",
+ "sk": [
+ {
+ "id": "U_00BB",
+ "text": "\u00BB"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ">",
+ "layer": "shift"
+ },
+ {
+ "id": "K_RBRKT",
+ "text": "}",
+ "layer": "shift"
+ }
+ ]
+ },
+ {
+ "id": "K_EQUAL",
+ "text": "+",
+ "layer": "shift"
+ },
+ {
+ "id": "K_HYPHEN",
+ "text": "-",
+ "layer": "default"
+ },
+ {
+ "id": "K_8",
+ "text": "*",
+ "layer": "shift"
+ },
+ {
+ "id": "K_SLASH",
+ "text": "/",
+ "layer": "default"
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "90",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_LOWER",
+ "text": "*abc*",
+ "width": "140",
+ "sp": "1",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "630",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "140",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "phone": {
+ "font": "Tahoma",
+ "layer": [
+ {
+ "id": "default",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "q"
+ },
+ {
+ "id": "K_W",
+ "text": "w"
+ },
+ {
+ "id": "K_E",
+ "text": "e"
+ },
+ {
+ "id": "K_R",
+ "text": "r"
+ },
+ {
+ "id": "K_T",
+ "text": "t"
+ },
+ {
+ "id": "K_Y",
+ "text": "y"
+ },
+ {
+ "id": "K_U",
+ "text": "u"
+ },
+ {
+ "id": "K_I",
+ "text": "i"
+ },
+ {
+ "id": "K_O",
+ "text": "o"
+ },
+ {
+ "id": "K_P",
+ "text": "p"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "a",
+ "pad": "50"
+ },
+ {
+ "id": "K_S",
+ "text": "s"
+ },
+ {
+ "id": "K_D",
+ "text": "d"
+ },
+ {
+ "id": "K_F",
+ "text": "f"
+ },
+ {
+ "id": "K_G",
+ "text": "g"
+ },
+ {
+ "id": "K_H",
+ "text": "h"
+ },
+ {
+ "id": "K_J",
+ "text": "j"
+ },
+ {
+ "id": "K_K",
+ "text": "k"
+ },
+ {
+ "id": "K_L",
+ "text": "l"
+ },
+ {
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "sp": "1",
+ "nextlayer": "shift"
+ },
+ {
+ "id": "K_Z",
+ "text": "z"
+ },
+ {
+ "id": "K_X",
+ "text": "x"
+ },
+ {
+ "id": "K_C",
+ "text": "c"
+ },
+ {
+ "id": "K_V",
+ "text": "v"
+ },
+ {
+ "id": "K_B",
+ "text": "b"
+ },
+ {
+ "id": "K_N",
+ "text": "n"
+ },
+ {
+ "id": "K_M",
+ "text": "m"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "100",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "150",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "610",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "150",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "shift",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_Q",
+ "text": "Q"
+ },
+ {
+ "id": "K_W",
+ "text": "W"
+ },
+ {
+ "id": "K_E",
+ "text": "E"
+ },
+ {
+ "id": "K_R",
+ "text": "R"
+ },
+ {
+ "id": "K_T",
+ "text": "T"
+ },
+ {
+ "id": "K_Y",
+ "text": "Y"
+ },
+ {
+ "id": "K_U",
+ "text": "U"
+ },
+ {
+ "id": "K_I",
+ "text": "I"
+ },
+ {
+ "id": "K_O",
+ "text": "O"
+ },
+ {
+ "id": "K_P",
+ "text": "P"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_A",
+ "text": "A",
+ "pad": "50"
+ },
+ {
+ "id": "K_S",
+ "text": "S"
+ },
+ {
+ "id": "K_D",
+ "text": "D"
+ },
+ {
+ "id": "K_F",
+ "text": "F"
+ },
+ {
+ "id": "K_G",
+ "text": "G"
+ },
+ {
+ "id": "K_H",
+ "text": "H"
+ },
+ {
+ "id": "K_J",
+ "text": "J"
+ },
+ {
+ "id": "K_K",
+ "text": "K"
+ },
+ {
+ "id": "K_L",
+ "text": "L"
+ },
+ {
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_SHIFT",
+ "text": "*Shift*",
+ "sp": "2",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_Z",
+ "text": "Z"
+ },
+ {
+ "id": "K_X",
+ "text": "X"
+ },
+ {
+ "id": "K_C",
+ "text": "C"
+ },
+ {
+ "id": "K_V",
+ "text": "V"
+ },
+ {
+ "id": "K_B",
+ "text": "B"
+ },
+ {
+ "id": "K_N",
+ "text": "N"
+ },
+ {
+ "id": "K_M",
+ "text": "M"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ".",
+ "layer": "default",
+ "sk": [
+ {
+ "text": ",",
+ "id": "K_COMMA",
+ "layer": "default"
+ },
+ {
+ "text": "!",
+ "id": "K_1",
+ "layer": "shift"
+ },
+ {
+ "text": "?",
+ "id": "K_SLASH",
+ "layer": "shift"
+ },
+ {
+ "text": "'",
+ "id": "K_QUOTE",
+ "layer": "default"
+ },
+ {
+ "text": "\"",
+ "id": "K_QUOTE",
+ "layer": "shift"
+ },
+ {
+ "text": "\\",
+ "id": "K_BKSLASH",
+ "layer": "default"
+ },
+ {
+ "text": ":",
+ "id": "K_COLON",
+ "layer": "shift"
+ },
+ {
+ "text": ";",
+ "id": "K_COLON",
+ "layer": "default"
+ }
+ ]
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_NUMLOCK",
+ "text": "*123*",
+ "width": "150",
+ "sp": "1",
+ "nextlayer": "numeric"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "610",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "150",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "numeric",
+ "row": [
+ {
+ "id": 1,
+ "key": [
+ {
+ "id": "K_1",
+ "text": "1"
+ },
+ {
+ "id": "K_2",
+ "text": "2"
+ },
+ {
+ "id": "K_3",
+ "text": "3"
+ },
+ {
+ "id": "K_4",
+ "text": "4"
+ },
+ {
+ "id": "K_5",
+ "text": "5"
+ },
+ {
+ "id": "K_6",
+ "text": "6"
+ },
+ {
+ "id": "K_7",
+ "text": "7"
+ },
+ {
+ "id": "K_8",
+ "text": "8"
+ },
+ {
+ "id": "K_9",
+ "text": "9"
+ },
+ {
+ "id": "K_0",
+ "text": "0"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "key": [
+ {
+ "id": "K_4",
+ "layer": "shift",
+ "text": "$",
+ "pad": "50"
+ },
+ {
+ "id": "K_2",
+ "layer": "shift",
+ "text": "@"
+ },
+ {
+ "id": "K_3",
+ "layer": "shift",
+ "text": "#"
+ },
+ {
+ "id": "K_5",
+ "layer": "shift",
+ "text": "%"
+ },
+ {
+ "id": "K_7",
+ "layer": "shift",
+ "text": "&"
+ },
+ {
+ "id": "K_HYPHEN",
+ "layer": "shift",
+ "text": "_"
+ },
+ {
+ "id": "K_EQUAL",
+ "text": "=",
+ "layer": "default"
+ },
+ {
+ "id": "K_BKSLASH",
+ "layer": "shift",
+ "text": "|"
+ },
+ {
+ "id": "K_BKSLASH",
+ "text": "\\",
+ "layer": "default"
+ },
+ {
+ "text": "",
+ "width": "10",
+ "sp": "10"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "key": [
+ {
+ "id": "K_LBRKT",
+ "text": "[",
+ "pad": "110",
+ "sk": [
+ {
+ "id": "U_00AB",
+ "text": "\u00AB"
+ },
+ {
+ "id": "K_COMMA",
+ "text": "<",
+ "layer": "shift"
+ },
+ {
+ "id": "K_LBRKT",
+ "text": "{",
+ "layer": "shift"
+ }
+ ]
+ },
+ {
+ "id": "K_9",
+ "layer": "shift",
+ "text": "("
+ },
+ {
+ "id": "K_0",
+ "layer": "shift",
+ "text": ")"
+ },
+ {
+ "id": "K_RBRKT",
+ "text": "]",
+ "sk": [
+ {
+ "id": "U_00BB",
+ "text": "\u00BB"
+ },
+ {
+ "id": "K_PERIOD",
+ "text": ">",
+ "layer": "shift"
+ },
+ {
+ "id": "K_RBRKT",
+ "text": "}",
+ "layer": "shift"
+ }
+ ]
+ },
+ {
+ "id": "K_EQUAL",
+ "layer": "shift",
+ "text": "+"
+ },
+ {
+ "id": "K_HYPHEN",
+ "text": "-"
+ },
+ {
+ "id": "K_8",
+ "layer": "shift",
+ "text": "*"
+ },
+ {
+ "id": "K_SLASH",
+ "text": "/"
+ },
+ {
+ "id": "K_BKSP",
+ "text": "*BkSp*",
+ "width": "100",
+ "sp": "1"
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "key": [
+ {
+ "id": "K_LOWER",
+ "text": "*abc*",
+ "width": "150",
+ "sp": "1",
+ "nextlayer": "default"
+ },
+ {
+ "id": "K_LOPT",
+ "text": "*Menu*",
+ "width": "120",
+ "sp": "1"
+ },
+ {
+ "id": "K_SPACE",
+ "text": "",
+ "width": "610",
+ "sp": "0"
+ },
+ {
+ "id": "K_ENTER",
+ "text": "*Enter*",
+ "width": "150",
+ "sp": "1"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kmn b/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kmn
new file mode 100644
index 0000000000..a2c33b6079
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kmn
@@ -0,0 +1,50 @@
+c This keyboard provides a reasonably complete example of
+c start-of-sentence detection, for use in testing #3621.
+store(&VERSION) '10.0'
+store(&NAME) 'start_of_sentence_3621'
+store(©RIGHT) '©'
+store(&KEYBOARDVERSION) '1.0'
+store(&TARGETS) 'any'
+store(&VISUALKEYBOARD) 'start_of_sentence_3621.kvks'
+store(&LAYOUTFILE) 'start_of_sentence_3621.keyman-touch-layout'
+
+begin Unicode > use(main)
+begin NewContext > use(NewContext)
+begin PostKeystroke > use(PostKeystroke)
+
+group(NewContext) readonly
+ c Any time we get a new context, by mouse click, tap,
+ c cursor movement, new document, etc, we'll try and
+ c determine the best layer to use
+ nomatch > use(nextLayer)
+
+group(PostKeystroke) readonly
+
+store(caps) 'A'..'Z'
+store(digit) '0'..'9'
+
+ c this is a heuristic that we can use until we support a CAPS layer (#3620):
+ c if we find two+ characters in capitals, leave us in shift layer,
+ c assuming the user hasn't just switched layer themselves. Once we have a
+ c proper CAPS layer, we'll get rid of this.
+ if(&layerChanged = "0") any(caps) any(caps) > context
+
+ c stay on the numeric layer if we are there already
+ if(&layerChanged = "0") if(&layer = 'numeric') any(digit) > context
+
+ c no other changes, so detect sentence or layer change, as long
+ c as the user hasn't attempted to change layer themselves
+ if(&layerChanged = "0") > use(nextLayer)
+
+group(nextLayer) readonly
+
+ store(sentencePunctuation) '.?!'
+ nul > layer('shift')
+ c note that 'readonly' layers do not need to use 'context' unless there is
+ c no other content on output of rule (empty output is illegal)
+ any(sentencePunctuation) ' ' > layer('shift')
+ any(sentencePunctuation) ' ' > layer('shift')
+ nomatch > layer('default')
+
+group(main) using keys
+
diff --git a/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kps b/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kps
new file mode 100644
index 0000000000..7868ce9e00
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kps
@@ -0,0 +1,67 @@
+
+
+
+ 15.0.114.0
+ 7.0
+
+
+
+ readme.htm
+
+
+
+
+
+
+
+
+
+ start_of_sentence_3621
+ ©
+
+
+
+
+
+ ..\build\start_of_sentence_3621.kmx
+
+ 0
+ .kmx
+
+
+ ..\build\start_of_sentence_3621.js
+
+ 0
+ .js
+
+
+ ..\build\start_of_sentence_3621.kvk
+
+ 0
+ .kvk
+
+
+ welcome.htm
+
+ 0
+ .htm
+
+
+ readme.htm
+
+ 0
+ .htm
+
+
+
+
+ start_of_sentence_3621
+ start_of_sentence_3621
+ 1.0
+
+ English
+
+
+
+
+
diff --git a/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kvks b/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kvks
new file mode 100644
index 0000000000..f9d21e8944
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/source/start_of_sentence_3621.kvks
@@ -0,0 +1,8 @@
+
+
+
+ 10.0
+ start_of_sentence_3621
+
+
+
diff --git a/common/test/keyboards/start_of_sentence_3621/source/welcome.htm b/common/test/keyboards/start_of_sentence_3621/source/welcome.htm
new file mode 100644
index 0000000000..5d14db8311
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/source/welcome.htm
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Start Using start_of_sentence_3621
+
+
+
+
+Start Using start_of_sentence_3621
+
+
+ start_of_sentence_3621 1.0 generated from template.
+
+
+Keyboard Layout
+
+
+
+
+
\ No newline at end of file
diff --git a/common/test/keyboards/start_of_sentence_3621/start_of_sentence_3621.keyboard_info b/common/test/keyboards/start_of_sentence_3621/start_of_sentence_3621.keyboard_info
new file mode 100644
index 0000000000..70b79803fa
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/start_of_sentence_3621.keyboard_info
@@ -0,0 +1,7 @@
+{
+ "license": "mit",
+ "languages": [
+ "en"
+ ],
+ "description": "start_of_sentence_3621 generated from template"
+}
diff --git a/common/test/keyboards/start_of_sentence_3621/start_of_sentence_3621.kpj b/common/test/keyboards/start_of_sentence_3621/start_of_sentence_3621.kpj
new file mode 100644
index 0000000000..064471c950
--- /dev/null
+++ b/common/test/keyboards/start_of_sentence_3621/start_of_sentence_3621.kpj
@@ -0,0 +1,102 @@
+
+
+
+ $PROJECTPATH\build
+ True
+ True
+ True
+ keyboard
+
+
+
+ id_51d2ccbdcbeeb798d532100b86252a19
+ start_of_sentence_3621.kmn
+ source\start_of_sentence_3621.kmn
+ 1.0
+ .kmn
+
+ start_of_sentence_3621
+ ©
+
+
+
+ id_feb278f5f21f5a2c56418aef3d610100
+ start_of_sentence_3621.kps
+ source\start_of_sentence_3621.kps
+
+ .kps
+
+ start_of_sentence_3621
+ ©
+
+
+
+ id_ede98e4633e239f933cbfd1f4e1b766c
+ HISTORY.md
+ HISTORY.md
+
+ .md
+
+
+ id_53e892b8b41cc4caece1cfd5ef21d6e7
+ LICENSE.md
+ LICENSE.md
+
+ .md
+
+
+ id_0730bb7c2e8f9ea2438b52e419dd86c9
+ README.md
+ README.md
+
+ .md
+
+
+ id_31c9e544d5ff29ebb5ee3006e39f5624
+ start_of_sentence_3621.keyboard_info
+ start_of_sentence_3621.keyboard_info
+
+ .keyboard_info
+
+
+ id_8b42366ff2333c0b6d85e2d23cf930d7
+ start_of_sentence_3621.kmx
+ source\..\build\start_of_sentence_3621.kmx
+
+ .kmx
+ id_feb278f5f21f5a2c56418aef3d610100
+
+
+ id_b0e85ab76446356d09d86b4187efbdad
+ start_of_sentence_3621.js
+ source\..\build\start_of_sentence_3621.js
+
+ .js
+ id_feb278f5f21f5a2c56418aef3d610100
+
+
+ id_3659e166ed1a8f97952e727f3a571a88
+ start_of_sentence_3621.kvk
+ source\..\build\start_of_sentence_3621.kvk
+
+ .kvk
+ id_feb278f5f21f5a2c56418aef3d610100
+
+
+ id_356e5d149c1e539356d72698c1e401a6
+ welcome.htm
+ source\welcome.htm
+
+ .htm
+ id_feb278f5f21f5a2c56418aef3d610100
+
+
+ id_8da344c4cea6f467013357fe099006f5
+ readme.htm
+ source\readme.htm
+
+ .htm
+ id_feb278f5f21f5a2c56418aef3d610100
+
+
+
diff --git a/developer/js/bundle.sh b/developer/js/bundle.sh
index 8a56304158..bda68c1c31 100644
--- a/developer/js/bundle.sh
+++ b/developer/js/bundle.sh
@@ -91,7 +91,8 @@ cp "$KEYMAN_MODELCOMPILER_ROOT/package-lock.json" "$KEYMAN_WIX_TEMP_MODELCOMPILE
# Yuck! ref: https://github.com/npm/cli/issues/3975#issuecomment-985305678
# ref: https://github.com/npm/cli/issues/2921
# can't use npm uninstall because it depends on @keymanapp/models-types being present!
-cat package.json | grep -v "@keymanapp/models-templates" | grep -v "@keymanapp/models-wordbreakers" > package.json || true
+
+cat "$KEYMAN_MODELCOMPILER_ROOT/package.json" | grep -v "@keymanapp/models-templates" | grep -v "@keymanapp/models-wordbreakers" > package.json || true
npm install kmtypes.tgz --production --no-optional
npm install --production --no-optional
diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json
index 4f215e4215..5051b19715 100644
--- a/developer/js/package-lock.json
+++ b/developer/js/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/lexical-model-compiler",
- "version": "15.0.177",
+ "version": "15.0.184",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/developer/js/package.json b/developer/js/package.json
index 271ad521a7..7a234cefc9 100644
--- a/developer/js/package.json
+++ b/developer/js/package.json
@@ -1,6 +1,6 @@
{
"name": "@keymanapp/lexical-model-compiler",
- "version": "15.0.177",
+ "version": "15.0.184",
"description": "Keyman Developer lexical model compiler",
"keywords": [
"keyboard",
@@ -37,14 +37,14 @@
"node": ">=12.0.0"
},
"dependencies": {
- "@keymanapp/models-types": "^15.0.177",
+ "@keymanapp/models-types": "^15.0.184",
"commander": "^3.0.0",
"typescript": "^3.8.3",
"xml2js": "^0.4.19"
},
"devDependencies": {
- "@keymanapp/models-templates": "^15.0.177",
- "@keymanapp/models-wordbreakers": "^15.0.177",
+ "@keymanapp/models-templates": "^15.0.184",
+ "@keymanapp/models-wordbreakers": "^15.0.184",
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.7",
"@types/node": "^10.14.6",
diff --git a/docs/build/linux-ubuntu.md b/docs/build/linux-ubuntu.md
index eb9438d7d5..7f315dcc83 100644
--- a/docs/build/linux-ubuntu.md
+++ b/docs/build/linux-ubuntu.md
@@ -6,15 +6,14 @@ On Linux, you can build the following projects:
* [Keyman for Linux](#keyman-for-linux)
* [Keyman Core](#keyman-core) (Linux only) (aka common/core/desktop)
-
-The following projects **cannot** be built on Linux because of outdated dependencies:
-
-
+
* Keyman for Android
* Keyman Core (wasm targets)
* Common/Web (aka common/core/web)
* KeymanWeb
+The following projects **cannot** be built on Linux:
+
* Keyman for Windows
* Keyman Developer
* Keyman for macOS
@@ -46,7 +45,7 @@ They are most easily installed with the `mk-build-deps` tool:
```bash
sudo apt update
-sudo apt install devscripts
+sudo apt install devscripts equivs
sudo mk-build-deps --install linux/debian/control
```
diff --git a/docs/build/macos.md b/docs/build/macos.md
index 04488e9c89..7c7a66f809 100644
--- a/docs/build/macos.md
+++ b/docs/build/macos.md
@@ -55,6 +55,12 @@ These dependencies are also listed below if you'd prefer to install manually.
brew install bash jq python3 meson ninja rustup-init coreutils pandoc rustup-init
```
+ On M1 only (as greadlink is not on the path otherwise in XCode):
+
+ ```shell
+ sudo ln -s /opt/homebrew/bin/greadlink /usr/local/bin/greadlink
+ ```
+
* Web: node.js, emscripten, wasm-pack, openjdk 8
```shell
diff --git a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj
index f6ce0d637a..c109ef472b 100644
--- a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj
+++ b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj
@@ -1058,8 +1058,8 @@
C06D37271F81F4E100F61AE0 /* Frameworks */,
C06D37281F81F4E100F61AE0 /* Headers */,
C06D37291F81F4E100F61AE0 /* Resources */,
- CEC0C66F2410B005003E1BCD /* ShellScript */,
- CE880430247F6EB6009BCA1A /* ShellScript */,
+ CEC0C66F2410B005003E1BCD /* Run Script - upload dsyms to Sentry */,
+ CE880430247F6EB6009BCA1A /* Run Script - set bundle versions */,
);
buildRules = (
);
@@ -1306,7 +1306,7 @@
shellPath = /bin/sh;
shellScript = "#if which swiftlint >/dev/null; then\n# swiftlint --config ../../.swiftlint.yml\n#else\n# echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\n#fi\n";
};
- CE880430247F6EB6009BCA1A /* ShellScript */ = {
+ CE880430247F6EB6009BCA1A /* Run Script - set bundle versions */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -1315,16 +1315,17 @@
);
inputPaths = (
);
+ name = "Run Script - set bundle versions";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
+ shellPath = "/usr/bin/env bash";
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n. \"$KEYMAN_ROOT/resources/build/xcode-utils.sh\"\n\nphaseSetBundleVersions true\n";
showEnvVarsInLog = 0;
};
- CEC0C66F2410B005003E1BCD /* ShellScript */ = {
+ CEC0C66F2410B005003E1BCD /* Run Script - upload dsyms to Sentry */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -1334,12 +1335,13 @@
inputPaths = (
"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}",
);
+ name = "Run Script - upload dsyms to Sentry";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
+ shellPath = "/usr/bin/env bash";
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n. \"$KEYMAN_ROOT/resources/build/xcode-utils.sh\"\n\nif [ ${UPLOAD_SENTRY:-false} = true ]; then\n # Calls resource script to perform the dSYM upload\n phaseSentryDsymUpload \"keyman-ios\"\nfi\n";
showEnvVarsInLog = 0;
};
diff --git a/ios/engine/KMEI/KeymanEngine/Classes/ckl.lproj/ResourceInfoView.strings b/ios/engine/KMEI/KeymanEngine/Classes/ckl.lproj/ResourceInfoView.strings
new file mode 100644
index 0000000000..9a3610130f
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/Classes/ckl.lproj/ResourceInfoView.strings
@@ -0,0 +1,2 @@
+/* Class = "UILabel"; text = "Scan this code to load this keyboard on another device"; ObjectID = "z2O-MT-IoV"; */
+"z2O-MT-IoV.text" = "Ka gǝ skan kod ǝni akuya ka gǝ vu kibod akwa devais damwa";
diff --git a/ios/engine/KMEI/KeymanEngine/Classes/hia.lproj/ResourceInfoView.strings b/ios/engine/KMEI/KeymanEngine/Classes/hia.lproj/ResourceInfoView.strings
new file mode 100644
index 0000000000..7eba570fc9
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/Classes/hia.lproj/ResourceInfoView.strings
@@ -0,0 +1,2 @@
+/* Class = "UILabel"; text = "Scan this code to load this keyboard on another device"; ObjectID = "z2O-MT-IoV"; */
+"z2O-MT-IoV.text" = "Afklat t fota nana code na guka klaft tana keyboard taghan unda sakwiɗi";
diff --git a/ios/engine/KMEI/KeymanEngine/Classes/mrt.lproj/ResourceInfoView.strings b/ios/engine/KMEI/KeymanEngine/Classes/mrt.lproj/ResourceInfoView.strings
new file mode 100644
index 0000000000..519409513e
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/Classes/mrt.lproj/ResourceInfoView.strings
@@ -0,0 +1,2 @@
+/* Class = "UILabel"; text = "Scan this code to load this keyboard on another device"; ObjectID = "z2O-MT-IoV"; */
+"z2O-MT-IoV.text" = "Kuga iu scan nur code ga fia keyboard arkra su nagum";
diff --git a/ios/engine/KMEI/KeymanEngine/ckl.lproj/Localizable.strings b/ios/engine/KMEI/KeymanEngine/ckl.lproj/Localizable.strings
new file mode 100644
index 0000000000..31d8855aa4
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/ckl.lproj/Localizable.strings
@@ -0,0 +1,254 @@
+/* A descriptive message used for errors when the app is already busy downloading */
+"alert-download-error-busy" = "Tsu ata kǝra downloading.";
+
+/* A descriptive message used when a download fails */
+"alert-download-error-detail" = "Su kura kal kal ʻya sakatu ata kǝra download ko vu su alukwa.";
+
+/* Title for a "download failed" alert */
+"alert-download-error-title" = "Su ʻya sakar download kura kal kal";
+
+/* Title for a general alert about errors */
+"alert-error-title" = "Su adai kura kal kal";
+
+/* A descriptive message used when no internet connection is detected */
+"alert-no-connection-detail" = "Adi ɓui ka tsǝbti Keyman server wɛ. Usɛ dzakti nkǝrti kadawm aɦǝla saka nkiɗu laka.";
+
+/* Title for a "no connection" alert */
+"alert-no-connection-title" = "Su kura kal kal ʻya akwa sakar connection";
+
+/* Short text for a 'back' navigational command. Used to return to the previous screen */
+"command-back" = "Mwari tubwa hi";
+
+/* Short text for a 'cancel' command. Used to back out of a menu or install process without making changes */
+"command-cancel" = "Kansǝl";
+
+/* Short text for a 'done' command. Used to back out of settings menus after changes have been made */
+"command-done" = "Kurai ʻyati";
+
+/* Short text for an 'install' command. Used to confirm installation of a package. */
+"command-install" = "Vu ko hau";
+
+/* Short text for a 'next' navigational command. Used to advance to the next screen */
+"command-next" = "Lǝkǝma";
+
+/* Short text for an 'OK' command. Used for some error alerts */
+"command-ok" = "Kal kal";
+
+/* Short text for confirmining 'uninstall' commands. */
+"command-uninstall" = "Faba ka kǝlba";
+
+/* Text for the command to uninstall a keyboard */
+"command-uninstall-keyboard" = "Kǝlba ka ɗalba kibod";
+
+/* Confirmation text to display before uninstalling a keyboard */
+"command-uninstall-keyboard-confirm" = "Gada bara ka kǝlba ka ɗalba kibod ǝni ya?";
+
+/* Text for the command to uninstall a lexical model */
+"command-uninstall-lexical-model" = "Kǝlba ka ɗalba dictionary";
+
+/* Confirmation text to display before uninstalling a lexical model */
+"command-uninstall-lexical-model-confirm" = "Gada bara ka kǝlba ka ɗalba dictionary ǝni ya?";
+
+/* Text for error when a keyboard cannot load properly */
+"error-loading-keyboard" = "Ta mǝzi ka vu ko hau kibod namtǝ gǝ yuwɛ wɛ";
+
+/* Text for error when a lexical model cannot load properly */
+"error-loading-lexical-model" = "Ta mǝzi ka vu ko hau dictionary namtǝ gǝ yuwɛ wɛ";
+
+/* Text for error when an installed file is unexpectedly missing */
+"error-missing-file" = "Fail namtǝ ndada bara adi ɓuidzi wɛ.";
+
+/* Text for error when an installed file is unexpectedly missing */
+"error-missing-file-critical" = "Fal laka nǝr ampani adi ɓuidzi wɛ ko ndǝ bara ka shang. Usɛ ɓǝla nkǝrti vu appari.";
+
+/* Text for errors in data received from search queries */
+"error-query-decoding" = "Serveri aka damicinidzi lakayere tubwar naurayere kulini";
+
+/* A descriptive message used when a download fails */
+"error-query-general" = "Su kura kal kal ata kǝra ʻya akwa kwa kwaliyir ndǝrɛ aka server";
+
+/* Text for error when a search query is unexpectedly empty */
+"error-query-no-data" = "Server adi ɓui ka na ndɛ amsa wɛ";
+
+/* Text for general errors where not much information is known */
+"error-unknown" = "Laifi laka kura ndǝta tǝmacini ku ʻya ko wakacini";
+
+/* Text for error when updating a resource: cannot download because no source is available */
+"error-update-no-link" = "Sǝr tsanti nǝr updateyere adiwɛ kadǝbar package ǝni";
+
+/* Text for error when updating a resource: Keyman does not know how to update the resource */
+"error-update-not-managed" = "Adiyata mǝzi update kariyere namtǝ engine nǝr Keyman adiyada manage wɛ";
+
+/* Text for the command to open the help page of a keyboard, as shown on resource information views */
+"info-command-help-keyboard" = "Dlarɛ nǝr kibod";
+
+/* Text for the command to open the help page of a lexical model, as shown on resource information views */
+"info-command-help-lexical-model" = "Dlarɛ nǝr dictionary";
+
+/* Text label for displaying a keyboard's version, as shown on resource information views */
+"info-label-version-keyboard" = "Vershon nǝr kibod";
+
+/* Text label for displaying a lexical model's version, as shown on resource information views */
+"info-label-version-lexical-model" = "Jiliyir dictionary";
+
+/* Label used for the "package info" / readme tab with the package installation prompt on phones. */
+"installer-label-package-info" = "Sǝr zǝndi ata kǝra package";
+
+/* Label used for the language-selection tab with the package installation prompt on phones. */
+"installer-label-select-languages" = "Tsarba Nya(yere)";
+
+/* Label used with a package's version, as seen within the package installation prompt. Example: "Version: 14.0.0" */
+"installer-label-version" = "Jili: %@";
+
+/* Section header for languages supported by a package, as seen within the package installation prompt */
+"installer-section-available-languages" = "Nyayere Nam Adai";
+
+/* Text for the help popup for changing keyboards with the globe key */
+"keyboard-help-change" = "Ntsani vi ǝni akuya ka gǝ pali kibod";
+
+/* Text for the command to exit the Keyman keyboard in favor of other keyboards installed on the system */
+"keyboard-menu-exit" = "Harti %@";
+
+/* Error installing a Keyman package - could not allocate a location to install it */
+"kmp-error-file-system" = "Su kura kal kal ʻya sakar vu package - su kura kal kal akwa file-system";
+
+/* Error installing a Keyman package - could not copy package files */
+"kmp-error-file-copying" = "Ada tsanti su kura kal kal sakar vu su - adi ɓui ka kopuba failyere nam kal kal wɛ";
+
+/* Error opening a Keyman package - package is not valid */
+"kmp-error-invalid" = "Package nǝr failari suwatǝdzi.";
+
+/* Error opening a Keyman package - it does not exist / the specified location is wrong */
+"kmp-error-missing" = "Pakeji ǝni musaman adi saga buidzi wɛ.";
+
+/* Error installing a Keyman package - expected resource (keyboard or dictionary) is missing */
+"kmp-error-missing-resource" = "Package ǝni adiyaka kibod ko dictionary namtǝ gǝ yuwɛ wɛ.";
+
+/* Error opening a Keyman package - cannot parse contents */
+"kmp-error-no-metadata" = "Package ǝni ndadi tsati tǝni kal kal wɛ - suyere nam akwa ndadi zǝndi wɛ.";
+
+/* Error opening a Keyman package - package's contents are for desktop platforms only */
+"kmp-error-unsupported" = "Jili pakeji ǝni adi aka sǝr dlarɛ ala divaisǝr ngɛ wɛ.";
+
+/* Error opening a Keyman package - package contains unexpected resource (keyboard or dictionary) type */
+"kmp-error-wrong-type" = "Package ǝni adiyaka jili su namtǝ ndǝ tǝmacini wɛ.";
+
+/* Title for the Installed Languages menu */
+"menu-installed-languages-title" = "Nyayere Namtǝ Ndǝ Vu ko hau";
+
+/* Section header for lexical models within a language-specific settings menu */
+"menu-langsettings-label-lexical-models" = "Dictionariyere";
+
+/* Section header for keyboards within a language-specific settings menu */
+"menu-langsettings-section-keyboards" = "Kibodyere";
+
+/* Section header for the settings toggles within a language-specific settings menu */
+"menu-langsettings-section-settings" = "Settingyere nǝr Nyayere";
+
+/* Title for the language-specific settings menus */
+"menu-langsettings-title" = "%@ Settingyere";
+
+/* Label for the toggle that enables corrections that is displayed within a language-specific settings menu */
+"menu-langsettings-toggle-correct" = "Enable corrections";
+
+/* Label for the toggle that enables predictions that is displayed within a language-specific settings menu */
+"menu-langsettings-toggle-predict" = "Enable predictions";
+
+/* Help message for a prompt that appears for confirming a lexical model download: language (1): lexical model (dictionary) name (2) */
+"menu-lexical-model-install-message" = "Gada bara ka vu ko hau dictionary ǝni ya?";
+
+/* Title for a prompt that appears for confirming a lexical model download: language (1): lexical model (dictionary) name (2) */
+"menu-lexical-model-install-title" = "%1$@: %2$@";
+
+/* Text for an info alert indicating that no lexical models are available */
+"menu-lexical-model-none-message" = "Dictionariyere adiyakwani wɛ";
+
+/* Title for the lexical model menu, a submenu of the language-specific settings menus */
+"menu-lexical-model-title" = "%@ Dictionariyere";
+
+/* Title for the keyboard picker */
+"menu-picker-title" = "Kibodyere";
+
+/* Primary text for the Settings menu option to report keyboard crashes */
+"menu-settings-error-report" = "Gyar ka dzǝ rupotu kura kal kalǝr su";
+
+/* Secondary text for the Settings menu option to report keyboard crashes */
+"menu-settings-error-report-description" = "Ata bara \"ɓuidzǝr lukwar su shang shang\"";
+
+/* Primary text for the Settings menu local-file package installation option */
+"menu-settings-install-from-file" = "Vu ko Hau Tubwar File";
+
+/* Secondary text for the Settings menu local-file package installation option */
+"menu-settings-install-from-file-description" = "Braus ala .kmp files";
+
+/* Primary text for the Settings menu option that displays the iOS system menu options for the app's keyboard */
+"menu-settings-system-keyboard-menu" = "Settingyere nǝr System Kibod";
+
+/* Label for the "Show Banner" toggle on the main settings screen */
+"menu-settings-show-banner" = "Tsanti Banner";
+
+/* Label for the "Get Started" automatic display toggle seen in the Settings menu */
+"menu-settings-startup-get-started" = "Tsanti 'Badicini Kǝthlǝr' ata mburntar kǝthlǝr";
+
+/* Title for the main Settings menu */
+"menu-settings-title" = "Settingyere nǝr Keyman";
+
+/* Secondary text showing current setting for spacebar caption - blank */
+"menu-settings-spacebar-hint-blank" = "Ta gǝta tsanti kapshion ko spesba";
+
+/* Secondary text showing current setting for spacebar caption - keyboard */
+"menu-settings-spacebar-hint-keyboard" = "Tsanti thlǝma kibod ata spesba";
+
+/* Secondary text showing current setting for spacebar caption - language */
+"menu-settings-spacebar-hint-language" = "Tsanti thlǝma nya ata spesba";
+
+/* Secondary text showing current setting for spacebar caption - language + keyboard */
+"menu-settings-spacebar-hint-languageKeyboard" = "Tsanti nya ba kibod ata spesba";
+
+/* Label for the "Spacebar Caption" item on the main settings screen */
+"menu-settings-spacebar-text" = "Kapshion nǝr spesba";
+
+/* Title for the "Spacebar Caption" settings screen */
+"menu-settings-spacebar-title" = "Kapshion nǝr spesba";
+
+/* Text showing name of spacebar caption - blank */
+"menu-settings-spacebar-item-blank" = "Kuraka rubwa akwa";
+
+/* Text showing name of spacebar caption - keyboard */
+"menu-settings-spacebar-item-keyboard" = "Kibod";
+
+/* Text showing name of spacebar caption - language */
+"menu-settings-spacebar-item-language" = "Nya";
+
+/* Text showing name of spacebar caption - language + keyboard */
+"menu-settings-spacebar-item-languageKeyboard" = "Nya ba kibod";
+
+/* Short text for notification: download failure for keyboard */
+"notification-download-failure-keyboard" = "Download nǝr Keyman ta ʻya wɛ";
+
+/* Short text for notification: download failure for lexical model */
+"notification-download-failure-lexical-model" = "Dictionary download ta ʻya wɛ";
+
+/* Short text for notification: download success for keyboard */
+"notification-download-success-keyboard" = "Ndǝ sǝgǝl aka kibod kura bwanai";
+
+/* Short text for notification: download success for lexical model */
+"notification-download-success-lexical-model" = "Ndǝ sǝgǝl aka lexical model kuraka bwanai";
+
+/* Short text for notification: downloading a keyboard */
+"notification-downloading-keyboard" = "Ata kǝra download kibod\U2026";
+
+/* Short text for notification: downloading a lexical model */
+"notification-downloading-lexical-model" = "Ata kǝra download dictionary\U2026";
+
+/* Short text for notification: an update is available */
+"notification-update-available" = "Update Adai";
+
+/* Short text for notification: currently updating */
+"notification-update-processing" = "Ata kǝra ʻya updating\U2026";
+
+/* Text indicating success at installing new keyboards or dictionaries */
+"success-install" = "Vudzi kuraka bwanai.";
+
+/* A title to use in alerts indicating 'success' at whatever task the user requested */
+"success-title" = "ʻYatǝdzi";
diff --git a/ios/engine/KMEI/KeymanEngine/ckl.lproj/Localizable.stringsdict b/ios/engine/KMEI/KeymanEngine/ckl.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..099e3b672c
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/ckl.lproj/Localizable.stringsdict
@@ -0,0 +1,118 @@
+
+
+
+
+ menu-langsettings-lexical-model-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u ndǝ vu ko hau dictionary
+ other
+ %u ndǝ vu ko hau dictionariyere
+
+
+ notification-update-failed
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u update adi ʻya wɛ
+ other
+ %u updateyere ada ʻya wɛ
+
+
+ notification-update-success
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u update ku ʻya
+ other
+ %u updateyere ku ʻyatǝdzi
+
+
+ settings-keyboards-installed-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u ndǝ vu ko hau kibod
+ other
+ %u ndǝ vu ko hau kibodyere
+
+
+ settings-languages-installed-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u ndǝ vu nya akwa
+ other
+ %u ndǝ vu nyayere akwa
+
+
+ package-default-found-keyboards
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ Bui %u kibod akwa package:
+ other
+ Ɓui %u kibodyere akwa package:
+
+
+ package-default-found-lexical-models
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ Ɓui %u dictionary akwa package:
+ other
+ Ɓui %u dictionariyere akwa package:
+
+
+
+
diff --git a/ios/engine/KMEI/KeymanEngine/hia.lproj/Localizable.strings b/ios/engine/KMEI/KeymanEngine/hia.lproj/Localizable.strings
new file mode 100644
index 0000000000..dfa9c396b0
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/hia.lproj/Localizable.strings
@@ -0,0 +1,254 @@
+/* A descriptive message used for errors when the app is already busy downloading */
+"alert-download-error-busy" = "Tun daga ghalaya t kal sukweɗe.";
+
+/* A descriptive message used when a download fails */
+"alert-download-error-detail" = "Haha ina magavata sirta kal sikweɗe ko fanta.";
+
+/* Title for a "download failed" alert */
+"alert-download-error-title" = "Kuskure magalo sarta kal sukweɗe";
+
+/* Title for a general alert about errors */
+"alert-error-title" = "Kuskure";
+
+/* A descriptive message used when no internet connection is detected */
+"alert-no-connection-detail" = "Da kusataka t Keyman server. Gamsa antika guleng t kima.";
+
+/* Title for a "no connection" alert */
+"alert-no-connection-title" = "Haha kuskura njagwata";
+
+/* Short text for a 'back' navigational command. Used to return to the previous screen */
+"command-back" = "Uhili";
+
+/* Short text for a 'cancel' command. Used to back out of a menu or install process without making changes */
+"command-cancel" = "Jata";
+
+/* Short text for a 'done' command. Used to back out of settings menus after changes have been made */
+"command-done" = "Kukuɗa";
+
+/* Short text for an 'install' command. Used to confirm installation of a package. */
+"command-install" = "Fanta";
+
+/* Short text for a 'next' navigational command. Used to advance to the next screen */
+"command-next" = "Unda siɗi";
+
+/* Short text for an 'OK' command. Used for some error alerts */
+"command-ok" = "Toh";
+
+/* Short text for confirmining 'uninstall' commands. */
+"command-uninstall" = "Fan bolwo";
+
+/* Text for the command to uninstall a keyboard */
+"command-uninstall-keyboard" = "Fan bol t keyboard nganawo";
+
+/* Confirmation text to display before uninstalling a keyboard */
+"command-uninstall-keyboard-confirm" = "Haka ɗow ka fan tana keyboard nure?";
+
+/* Text for the command to uninstall a lexical model */
+"command-uninstall-lexical-model" = "Fan bol t dictionary wo";
+
+/* Confirmation text to display before uninstalling a lexical model */
+"command-uninstall-lexical-model-confirm" = "Haka ɗow fan tana dictionary nure?";
+
+/* Text for error when a keyboard cannot load properly */
+"error-loading-keyboard" = "Ha da wawata klaft keyboard unda ɗowal wo";
+
+/* Text for error when a lexical model cannot load properly */
+"error-loading-lexical-model" = "Ha da wawata klaft dictionary unda ɗowal wo";
+
+/* Text for error when an installed file is unexpectedly missing */
+"error-missing-file" = "File unda ɗowal na javabolwo.";
+
+/* Text for error when an installed file is unexpectedly missing */
+"error-missing-file-critical" = "File unda bla na java bolwo. Gamsa avira tikan tina fanta ngana.";
+
+/* Text for errors in data received from search queries */
+"error-query-decoding" = "Server ngana ɗakanana haha ina kol ɗughwana amndiya]";
+
+/* A descriptive message used when a download fails */
+"error-query-general" = "Haha kuskura kor gwaɗa nda server";
+
+/* Text for error when a search query is unexpectedly empty */
+"error-query-no-data" = "Server ngana na ha mog thlina wo";
+
+/* Text for general errors where not much information is known */
+"error-unknown" = "Kuskure kol sinantal faravata";
+
+/* Text for error when updating a resource: cannot download because no source is available */
+"error-update-no-link" = "Ha inunda nighangal da maran tinunda sa magawo anga nana package nawo";
+
+/* Text for error when updating a resource: Keyman does not know how to update the resource */
+"error-update-not-managed" = "Ha da javat tinahunda sa magal ghalayawo kol magatal nda keyman engine wo";
+
+/* Text for the command to open the help page of a keyboard, as shown on resource information views */
+"info-command-help-keyboard" = "Keyboard unda t tamoko";
+
+/* Text for the command to open the help page of a lexical model, as shown on resource information views */
+"info-command-help-lexical-model" = "Dictionary tamoko";
+
+/* Text label for displaying a keyboard's version, as shown on resource information views */
+"info-label-version-keyboard" = "Sangabt keyboard";
+
+/* Text label for displaying a lexical model's version, as shown on resource information views */
+"info-label-version-lexical-model" = "Sangabt dictionary";
+
+/* Label used for the "package info" / readme tab with the package installation prompt on phones. */
+"installer-label-package-info" = "Package Info";
+
+/* Label used for the language-selection tab with the package installation prompt on phones. */
+"installer-label-select-languages" = "Klabt gwaɗa luwaha";
+
+/* Label used with a package's version, as seen within the package installation prompt. Example: "Version: 14.0.0" */
+"installer-label-version" = "Sangabt: %@";
+
+/* Section header for languages supported by a package, as seen within the package installation prompt */
+"installer-section-available-languages" = "Gwaɗaha luwunda hahaɗe";
+
+/* Text for the help popup for changing keyboards with the globe key */
+"keyboard-help-change" = "Aff fa jiv ahdina ka mbiɗat keyboard";
+
+/* Text for the command to exit the Keyman keyboard in favor of other keyboards installed on the system */
+"keyboard-menu-exit" = "Funta %@";
+
+/* Error installing a Keyman package - could not allocate a location to install it */
+"kmp-error-file-system" = "Kuskura fant package - file - system kuskure";
+
+/* Error installing a Keyman package - could not copy package files */
+"kmp-error-file-copying" = "Kuskura fant package - klafba t files unda ɗowal wo";
+
+/* Error opening a Keyman package - package is not valid */
+"kmp-error-invalid" = "Package's file na ɗughwan buwo.";
+
+/* Error opening a Keyman package - it does not exist / the specified location is wrong */
+"kmp-error-missing" = "Inunda sinaglo package haɗuwo ha mog thlinawo.";
+
+/* Error installing a Keyman package - expected resource (keyboard or dictionary) is missing */
+"kmp-error-missing-resource" = "Nana package nana haɗ nda keyboard unda ɗowal wo ko dictionary.";
+
+/* Error opening a Keyman package - cannot parse contents */
+"kmp-error-no-metadata" = "Nana package nana babol ɗughwanawo - contents sinanbolwo.";
+
+/* Error opening a Keyman package - package's contents are for desktop platforms only */
+"kmp-error-unsupported" = "Nana package nana haɗ ta fanast jiv t device ghahaghuwo.";
+
+/* Error opening a Keyman package - package contains unexpected resource (keyboard or dictionary) type */
+"kmp-error-wrong-type" = "Nana package nana haɗ nda inahunda ɗowal wo.";
+
+/* Title for the Installed Languages menu */
+"menu-installed-languages-title" = "Gwaɗaha luwunda fanlo";
+
+/* Section header for lexical models within a language-specific settings menu */
+"menu-langsettings-label-lexical-models" = "Dictionaries";
+
+/* Section header for keyboards within a language-specific settings menu */
+"menu-langsettings-section-keyboards" = "Keyboards";
+
+/* Section header for the settings toggles within a language-specific settings menu */
+"menu-langsettings-section-settings" = "Language Settings";
+
+/* Title for the language-specific settings menus */
+"menu-langsettings-title" = "%@ Settings";
+
+/* Label for the toggle that enables corrections that is displayed within a language-specific settings menu */
+"menu-langsettings-toggle-correct" = "Magaghva kuskure";
+
+/* Label for the toggle that enables predictions that is displayed within a language-specific settings menu */
+"menu-langsettings-toggle-predict" = "Magaghva predictions";
+
+/* Help message for a prompt that appears for confirming a lexical model download: language (1): lexical model (dictionary) name (2) */
+"menu-lexical-model-install-message" = "Ɗowka ka fant tana dictionary na re?";
+
+/* Title for a prompt that appears for confirming a lexical model download: language (1): lexical model (dictionary) name (2) */
+"menu-lexical-model-install-title" = "%1$@: %2$@";
+
+/* Text for an info alert indicating that no lexical models are available */
+"menu-lexical-model-none-message" = "Haɗ dictionaries wo";
+
+/* Title for the lexical model menu, a submenu of the language-specific settings menus */
+"menu-lexical-model-title" = "%@ Dictionaries";
+
+/* Title for the keyboard picker */
+"menu-picker-title" = "Keyboards";
+
+/* Primary text for the Settings menu option to report keyboard crashes */
+"menu-settings-error-report" = "Avathla kor t kuskure";
+
+/* Secondary text for the Settings menu option to report keyboard crashes */
+"menu-settings-error-report-description" = "Ma da ɗowt \"wativ sosaya\"";
+
+/* Primary text for the Settings menu local-file package installation option */
+"menu-settings-install-from-file" = "Fanta avla File";
+
+/* Secondary text for the Settings menu local-file package installation option */
+"menu-settings-install-from-file-description" = "Browse anga .kmp files";
+
+/* Primary text for the Settings menu option that displays the iOS system menu options for the app's keyboard */
+"menu-settings-system-keyboard-menu" = "System Keyboard Settings";
+
+/* Label for the "Show Banner" toggle on the main settings screen */
+"menu-settings-show-banner" = "Marant Banner";
+
+/* Label for the "Get Started" automatic display toggle seen in the Settings menu */
+"menu-settings-startup-get-started" = "Marant 'A fuɗa' t startup";
+
+/* Title for the main Settings menu */
+"menu-settings-title" = "Keyman Settings";
+
+/* Secondary text showing current setting for spacebar caption - blank */
+"menu-settings-spacebar-hint-blank" = "Eh marantaka t caption taghan spacebar";
+
+/* Secondary text showing current setting for spacebar caption - keyboard */
+"menu-settings-spacebar-hint-keyboard" = "Marant keyboard zirin taghan spacebar";
+
+/* Secondary text showing current setting for spacebar caption - language */
+"menu-settings-spacebar-hint-language" = "Marant gwaɗa luwa taghan spacebar";
+
+/* Secondary text showing current setting for spacebar caption - language + keyboard */
+"menu-settings-spacebar-hint-languageKeyboard" = "Marant gwaɗa luwa nda keyboard zirini taghan spacebar";
+
+/* Label for the "Spacebar Caption" item on the main settings screen */
+"menu-settings-spacebar-text" = "Spacebar Caption";
+
+/* Title for the "Spacebar Caption" settings screen */
+"menu-settings-spacebar-title" = "Spacebar Caption";
+
+/* Text showing name of spacebar caption - blank */
+"menu-settings-spacebar-item-blank" = "Ha konuwo";
+
+/* Text showing name of spacebar caption - keyboard */
+"menu-settings-spacebar-item-keyboard" = "Keyboard";
+
+/* Text showing name of spacebar caption - language */
+"menu-settings-spacebar-item-language" = "Gwaɗa luwa";
+
+/* Text showing name of spacebar caption - language + keyboard */
+"menu-settings-spacebar-item-languageKeyboard" = "Gwaɗa luwa nda keyboard";
+
+/* Short text for notification: download failure for keyboard */
+"notification-download-failure-keyboard" = "Keyboard sangatana kalavukala";
+
+/* Short text for notification: download failure for lexical model */
+"notification-download-failure-lexical-model" = "Kalavukala k sangat dictionary";
+
+/* Short text for notification: download success for keyboard */
+"notification-download-success-keyboard" = "Keyboard na sangasal ɗughwana";
+
+/* Short text for notification: download success for lexical model */
+"notification-download-success-lexical-model" = "Lexical model sangasal ɗughwana";
+
+/* Short text for notification: downloading a keyboard */
+"notification-downloading-keyboard" = "Sangat keyboard\U2026";
+
+/* Short text for notification: downloading a lexical model */
+"notification-downloading-lexical-model" = "Sangat dictionary\U2026";
+
+/* Short text for notification: an update is available */
+"notification-update-available" = "Update hahaɗe";
+
+/* Short text for notification: currently updating */
+"notification-update-processing" = "Updating\U2026";
+
+/* Text indicating success at installing new keyboards or dictionaries */
+"success-install" = "Fanfal ɗughwana.";
+
+/* A title to use in alerts indicating 'success' at whatever task the user requested */
+"success-title" = "Magat saʻa";
diff --git a/ios/engine/KMEI/KeymanEngine/hia.lproj/Localizable.stringsdict b/ios/engine/KMEI/KeymanEngine/hia.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..b8e5184faa
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/hia.lproj/Localizable.stringsdict
@@ -0,0 +1,132 @@
+
+
+
+
+ menu-langsettings-lexical-model-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ zero
+ %uDictionary fan falo
+ one
+ %u dictionary fan falo
+ other
+ %u dictionary fan lo
+
+
+ notification-update-failed
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ zero
+ %u update kalavukala
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u update kalavukala
+ other
+ %u update kalavukala
+
+
+ notification-update-success
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ zero
+ %u update kalavukala
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u update kalavukala
+ other
+ %u update kalavukala
+
+
+ settings-keyboards-installed-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ zero
+ %u keyboard fanfalo
+ one
+ %u keyboard fanfalo
+ other
+ %u keyboard fan falo
+
+
+ settings-languages-installed-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ zero
+ %u gwaɗa luwa falo
+ one
+ %u gwaɗa luwa fanfalo
+ other
+ %u gwaɗa luwa fanfalo
+
+
+ package-default-found-keyboards
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ zero
+ Javat %u keyboard an package:
+ one
+ Javat %u keyboard an package:
+ other
+ Javat %u keyboard an package:
+
+
+ package-default-found-lexical-models
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ zero
+ Javat %u dictionary in package:
+ one
+ Javat %u dictionary an package:
+ other
+ Javat %u dictionary an package:
+
+
+
+
diff --git a/ios/engine/KMEI/KeymanEngine/mrt.lproj/Localizable.strings b/ios/engine/KMEI/KeymanEngine/mrt.lproj/Localizable.strings
new file mode 100644
index 0000000000..db3774014b
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/mrt.lproj/Localizable.strings
@@ -0,0 +1,254 @@
+/* A descriptive message used for errors when the app is already busy downloading */
+"alert-download-error-busy" = "Mji vur iu downloading.";
+
+/* A descriptive message used when a download fails */
+"alert-download-error-detail" = "Error a irkir latur download akiya mai installation.";
+
+/* Title for a "download failed" alert */
+"alert-download-error-title" = "Download error";
+
+/* Title for a general alert about errors */
+"alert-error-title" = "Error";
+
+/* A descriptive message used when no internet connection is detected */
+"alert-no-connection-detail" = "Acittu thlana Keyman server mai. Manki ngilaba sikari.";
+
+/* Title for a "no connection" alert */
+"alert-no-connection-title" = "Connection Error";
+
+/* Short text for a 'back' navigational command. Used to return to the previous screen */
+"command-back" = "Yikuɗu";
+
+/* Short text for a 'cancel' command. Used to back out of a menu or install process without making changes */
+"command-cancel" = "Kukulna";
+
+/* Short text for a 'done' command. Used to back out of settings menus after changes have been made */
+"command-done" = "Akuɗiri";
+
+/* Short text for an 'install' command. Used to confirm installation of a package. */
+"command-install" = "Install";
+
+/* Short text for a 'next' navigational command. Used to advance to the next screen */
+"command-next" = "Nagum";
+
+/* Short text for an 'OK' command. Used for some error alerts */
+"command-ok" = "OK";
+
+/* Short text for confirmining 'uninstall' commands. */
+"command-uninstall" = "Uninstall";
+
+/* Text for the command to uninstall a keyboard */
+"command-uninstall-keyboard" = "Uninstall keyboard";
+
+/* Confirmation text to display before uninstalling a keyboard */
+"command-uninstall-keyboard-confirm" = "Nagu ayu ga uninstall nur keyboard ya?";
+
+/* Text for the command to uninstall a lexical model */
+"command-uninstall-lexical-model" = "Uninstall dictionary";
+
+/* Confirmation text to display before uninstalling a lexical model */
+"command-uninstall-lexical-model-confirm" = "Nagu ayu ga uninstall nur dictionary ya?";
+
+/* Text for error when a keyboard cannot load properly */
+"error-loading-keyboard" = "Acitu iu lodi nur keyboard dun mji vur ngu mai";
+
+/* Text for error when a lexical model cannot load properly */
+"error-loading-lexical-model" = "Acitu iu lodi nur dictionary mji vur ngu";
+
+/* Text for error when an installed file is unexpectedly missing */
+"error-missing-file" = "Mji acittu thlia file nagum mai.";
+
+/* Text for error when an installed file is unexpectedly missing */
+"error-missing-file-critical" = "Critical file mji a lari mai. Manki bura fia app.";
+
+/* Text for errors in data received from search queries */
+"error-query-decoding" = "Server ari naja vur thlia bone nur iu thlir duri";
+
+/* A descriptive message used when a download fails */
+"error-query-general" = "Error nur ndir aga server";
+
+/* Text for error when a search query is unexpectedly empty */
+"error-query-no-data" = "Server ari naja vur ndir mai";
+
+/* Text for general errors where not much information is known */
+"error-unknown" = "Error nagum a irkir";
+
+/* Text for error when updating a resource: cannot download because no source is available */
+"error-update-no-link" = "Lagu a'i mai nur su bilin anu package ku";
+
+/* Text for error when updating a resource: Keyman does not know how to update the resource */
+"error-update-not-managed" = "Acittu fia su bilin kuku Keyman vur iu thlir arkra";
+
+/* Text for the command to open the help page of a keyboard, as shown on resource information views */
+"info-command-help-keyboard" = "Ɓa nur Keyboard";
+
+/* Text for the command to open the help page of a lexical model, as shown on resource information views */
+"info-command-help-lexical-model" = "Ɓa nur Dictionary";
+
+/* Text label for displaying a keyboard's version, as shown on resource information views */
+"info-label-version-keyboard" = "Version nur Keyboard";
+
+/* Text label for displaying a lexical model's version, as shown on resource information views */
+"info-label-version-lexical-model" = "Version nur Dictionary";
+
+/* Label used for the "package info" / readme tab with the package installation prompt on phones. */
+"installer-label-package-info" = "Labar nur Package";
+
+/* Label used for the language-selection tab with the package installation prompt on phones. */
+"installer-label-select-languages" = "Caɗu Ŋya ari (yer)";
+
+/* Label used with a package's version, as seen within the package installation prompt. Example: "Version: 14.0.0" */
+"installer-label-version" = "Version: %@";
+
+/* Section header for languages supported by a package, as seen within the package installation prompt */
+"installer-section-available-languages" = "Ŋya kuku aʻi";
+
+/* Text for the help popup for changing keyboards with the globe key */
+"keyboard-help-change" = "Ncina uvun ga pubila keyboard";
+
+/* Text for the command to exit the Keyman keyboard in favor of other keyboards installed on the system */
+"keyboard-menu-exit" = "Ghaɗu %@";
+
+/* Error installing a Keyman package - could not allocate a location to install it */
+"kmp-error-file-system" = "Error nur fia package - error nur file-system";
+
+/* Error installing a Keyman package - could not copy package files */
+"kmp-error-file-copying" = "Errror nur fu package - acittu huri jili file mai";
+
+/* Error opening a Keyman package - package is not valid */
+"kmp-error-invalid" = "Package file a mdzu.";
+
+/* Error opening a Keyman package - it does not exist / the specified location is wrong */
+"kmp-error-missing" = "Jili package ku a'i mai.";
+
+/* Error installing a Keyman package - expected resource (keyboard or dictionary) is missing */
+"kmp-error-missing-resource" = "Package ku naja aga jili keyboard akiya mai dictionary du mji a jauba.";
+
+/* Error opening a Keyman package - cannot parse contents */
+"kmp-error-no-metadata" = "Mji a pa package ku munagu mai - suku akwa mji kra sini mai.";
+
+/* Error opening a Keyman package - package's contents are for desktop platforms only */
+"kmp-error-unsupported" = "Package ku naja nda mchaku ɓar udzu anu kwahir nasara ginyi mai.";
+
+/* Error opening a Keyman package - package contains unexpected resource (keyboard or dictionary) type */
+"kmp-error-wrong-type" = "This package does not contain the expected resource type.";
+
+/* Title for the Installed Languages menu */
+"menu-installed-languages-title" = "Fia Ŋya yer";
+
+/* Section header for lexical models within a language-specific settings menu */
+"menu-langsettings-label-lexical-models" = "Dictionaries";
+
+/* Section header for keyboards within a language-specific settings menu */
+"menu-langsettings-section-keyboards" = "Keyboards";
+
+/* Section header for the settings toggles within a language-specific settings menu */
+"menu-langsettings-section-settings" = "Language Settings";
+
+/* Title for the language-specific settings menus */
+"menu-langsettings-title" = "%@ Settings";
+
+/* Label for the toggle that enables corrections that is displayed within a language-specific settings menu */
+"menu-langsettings-toggle-correct" = "Enable corrections";
+
+/* Label for the toggle that enables predictions that is displayed within a language-specific settings menu */
+"menu-langsettings-toggle-predict" = "Enable predictions";
+
+/* Help message for a prompt that appears for confirming a lexical model download: language (1): lexical model (dictionary) name (2) */
+"menu-lexical-model-install-message" = "Nagu ayu ga fia dictionary ya?";
+
+/* Title for a prompt that appears for confirming a lexical model download: language (1): lexical model (dictionary) name (2) */
+"menu-lexical-model-install-title" = "%1$@: %2$@";
+
+/* Text for an info alert indicating that no lexical models are available */
+"menu-lexical-model-none-message" = "Dictionaries aʻi mai";
+
+/* Title for the lexical model menu, a submenu of the language-specific settings menus */
+"menu-lexical-model-title" = "%@ Dictionaries";
+
+/* Title for the keyboard picker */
+"menu-picker-title" = "Keyboards";
+
+/* Primary text for the Settings menu option to report keyboard crashes */
+"menu-settings-error-report" = "Ngeri Wula su kra kalkal";
+
+/* Secondary text for the Settings menu option to report keyboard crashes */
+"menu-settings-error-report-description" = "May require \"full access\"";
+
+/* Primary text for the Settings menu local-file package installation option */
+"menu-settings-install-from-file" = "Install File yer";
+
+/* Secondary text for the Settings menu local-file package installation option */
+"menu-settings-install-from-file-description" = "Browse for .kmp files";
+
+/* Primary text for the Settings menu option that displays the iOS system menu options for the app's keyboard */
+"menu-settings-system-keyboard-menu" = "System Keyboard Settings";
+
+/* Label for the "Show Banner" toggle on the main settings screen */
+"menu-settings-show-banner" = "Ncha Banner";
+
+/* Label for the "Get Started" automatic display toggle seen in the Settings menu */
+"menu-settings-startup-get-started" = "Ncha ʻBaditsiniʻ u startup";
+
+/* Title for the main Settings menu */
+"menu-settings-title" = "Keyman Settings";
+
+/* Secondary text showing current setting for spacebar caption - blank */
+"menu-settings-spacebar-hint-blank" = "Asuka ga ncha ruɓutsini ar spaceba mai";
+
+/* Secondary text showing current setting for spacebar caption - keyboard */
+"menu-settings-spacebar-hint-keyboard" = "Ncha thlimur keyboard arkra spaceba";
+
+/* Secondary text showing current setting for spacebar caption - language */
+"menu-settings-spacebar-hint-language" = "Ncha thlimur ŋya ar spaceba";
+
+/* Secondary text showing current setting for spacebar caption - language + keyboard */
+"menu-settings-spacebar-hint-languageKeyboard" = "Ŋcha thlimu ŋya baɗa keyboard ar spaceba";
+
+/* Label for the "Spacebar Caption" item on the main settings screen */
+"menu-settings-spacebar-text" = "Ruɓutsini ar spaceba";
+
+/* Title for the "Spacebar Caption" settings screen */
+"menu-settings-spacebar-title" = "Ruɓutsini ar spaceba";
+
+/* Text showing name of spacebar caption - blank */
+"menu-settings-spacebar-item-blank" = "Kra ga ruɓutsini";
+
+/* Text showing name of spacebar caption - keyboard */
+"menu-settings-spacebar-item-keyboard" = "Keyboard";
+
+/* Text showing name of spacebar caption - language */
+"menu-settings-spacebar-item-language" = "Ŋya";
+
+/* Text showing name of spacebar caption - language + keyboard */
+"menu-settings-spacebar-item-languageKeyboard" = "Ŋya baɗa keyboard";
+
+/* Short text for notification: download failure for keyboard */
+"notification-download-failure-keyboard" = "Keyboard download aŋgiliri";
+
+/* Short text for notification: download failure for lexical model */
+"notification-download-failure-lexical-model" = "Dictionary download a ngiliri";
+
+/* Short text for notification: download success for keyboard */
+"notification-download-success-keyboard" = "Keyboard successfully downloaded";
+
+/* Short text for notification: download success for lexical model */
+"notification-download-success-lexical-model" = "Lexical model successfully downloaded";
+
+/* Short text for notification: downloading a keyboard */
+"notification-downloading-keyboard" = "Downloading keyboard\U2026";
+
+/* Short text for notification: downloading a lexical model */
+"notification-downloading-lexical-model" = "Downloading dictionary\U2026";
+
+/* Short text for notification: an update is available */
+"notification-update-available" = "Update aʻi";
+
+/* Short text for notification: currently updating */
+"notification-update-processing" = "Updating\U2026";
+
+/* Text indicating success at installing new keyboards or dictionaries */
+"success-install" = "Installed successfully.";
+
+/* A title to use in alerts indicating 'success' at whatever task the user requested */
+"success-title" = "Success";
diff --git a/ios/engine/KMEI/KeymanEngine/mrt.lproj/Localizable.stringsdict b/ios/engine/KMEI/KeymanEngine/mrt.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..d77786d7cf
--- /dev/null
+++ b/ios/engine/KMEI/KeymanEngine/mrt.lproj/Localizable.stringsdict
@@ -0,0 +1,118 @@
+
+
+
+
+ menu-langsettings-lexical-model-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u dictionary installed
+ other
+ %u dictionaries installed
+
+
+ notification-update-failed
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u update a ngiliri
+ other
+ %u updates a ngiliri
+
+
+ notification-update-success
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u update a iu munagu
+ other
+ %u update successful
+
+
+ settings-keyboards-installed-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u keyboard installed
+ other
+ %u keyboard installed
+
+
+ settings-languages-installed-count
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ %u Installed nur ŋya
+ other
+ %u language nur ŋya
+
+
+ package-default-found-keyboards
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ Thlia mji %u keyboard akwa package:
+ other
+ Athlia mji %u keyboard akwa package:
+
+
+ package-default-found-lexical-models
+
+ NSStringLocalizedFormatKey
+ %#@count@
+ count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ u
+ one
+ Athlia mji %u dictionary akwa package:
+ other
+ Athlia mji %u dictionary akwa package:
+
+
+
+
diff --git a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj
index 692a59994b..ae30f12013 100644
--- a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj
+++ b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj
@@ -709,9 +709,9 @@
981AFADC19EF44DE006706BF /* Embed App Extensions */,
37BC8FF91DE83B40006AEBFF /* Headers */,
C01AB5981F8343F7009B37D3 /* Embed Frameworks */,
- CE7E13D8240E285800252C00 /* ShellScript */,
- 989E4DB91B1EB5C200A345FB /* Run Script */,
- CE002CB32408B372002026CE /* ShellScript */,
+ CE7E13D8240E285800252C00 /* Run Script - set versions */,
+ 989E4DB91B1EB5C200A345FB /* Run Script - update plists and lint */,
+ CE002CB32408B372002026CE /* Run Script - upload dsyms to sentry */,
);
buildRules = (
);
@@ -931,22 +931,22 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 989E4DB91B1EB5C200A345FB /* Run Script */ = {
+ 989E4DB91B1EB5C200A345FB /* Run Script - update plists and lint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Run Script";
+ name = "Run Script - update plists and lint";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
+ shellPath = "/usr/bin/env bash";
shellScript = "verstr1=$(/usr/libexec/PlistBuddy -c \"Print CFBundleShortVersionString\" \"$SRCROOT/Keyman-Info.plist\")\nverstr2=$(/usr/libexec/PlistBuddy -c \"Print CFBundleVersion\" \"$SRCROOT/Keyman-Info.plist\")\n/usr/libexec/PlistBuddy \"$SRCROOT/Settings.bundle/Root.plist\" -c \"set PreferenceSpecifiers:0:DefaultValue $verstr1 (build $verstr2)\"\n\nif which swiftlint >/dev/null; then\n swiftlint --config ../../.swiftlint.yml\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
showEnvVarsInLog = 0;
};
- CE002CB32408B372002026CE /* ShellScript */ = {
+ CE002CB32408B372002026CE /* Run Script - upload dsyms to sentry */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -956,12 +956,13 @@
inputPaths = (
"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}",
);
+ name = "Run Script - upload dsyms to sentry";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/bash;
+ shellPath = "/usr/bin/env bash";
shellScript = ". \"$KEYMAN_ROOT/resources/build/xcode-utils.sh\"\n\nif [ ${UPLOAD_SENTRY:-false} = true ]; then\n # Calls resource script to perform the dSYM upload\n phaseSentryDsymUpload \"keyman-ios\"\nfi\n";
};
CE06AA671F161422006D91C3 /* Run Script */ = {
@@ -978,7 +979,7 @@
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint --config ../../.swiftlint.yml\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
- CE7E13D8240E285800252C00 /* ShellScript */ = {
+ CE7E13D8240E285800252C00 /* Run Script - set versions */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -987,12 +988,13 @@
);
inputPaths = (
);
+ name = "Run Script - set versions";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
+ shellPath = "/usr/bin/env bash";
shellScript = ". \"$KEYMAN_ROOT/resources/build/xcode-utils.sh\"\n\n# Calls resource script to update build products' versioning.\n# true: applies VERSION_WITH_TAG to custom KeymanVersionWithTag plist member used for in-app display\nphaseSetBundleVersions true\n\n# Also updates the version string for Settings\nsetSettingsBundleVersion\n";
showEnvVarsInLog = 0;
};
diff --git a/ios/keyman/Keyman/Keyman/ckl.lproj/Localizable.strings b/ios/keyman/Keyman/Keyman/ckl.lproj/Localizable.strings
new file mode 100644
index 0000000000..08d23262a3
--- /dev/null
+++ b/ios/keyman/Keyman/Keyman/ckl.lproj/Localizable.strings
@@ -0,0 +1,81 @@
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-add-title" = "Dzakti Bookmark";
+
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-none" = "Bookmarkyere adiwɛ";
+
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-title" = "Bookmarkyere";
+
+/* Used to confirm a user's desire to install a package */
+"confirm-install" = "Vu akwa";
+
+/* The label for the toggle to stop automatically showing the "Get Started" tutorial popup. */
+"disable-get-started" = "Ta gǝta tsanti kadwam";
+
+/* Indicates an error opening a web page requested by a user */
+"error-opening-page" = "Gadiyata Mǝzi Mburnta Peji Wɛ";
+
+/* Long-form used when installing a font in order to display a language properly. */
+"font-install-description" = "Tsukwar Vu Akwa akuya ka %@ su tsantidzi kal kal akwa shanga appyere nǝngɛ";
+
+/* The name of the iOS Settings menu option for keyboards */
+"ios-settings-keyboards" = "Kibodyere";
+
+/* The name of the iOS Settings menu option for giving the keyboard full access. (The menu entry
+underneath the app's name within the app-specific keyboard menu.) */
+"ios-settings-allow-full-access" = "Ada Gyar Ka Ndɛ Lukwa";
+
+/* Short-form used when installing a font in order to display a language properly. */
+"language-for-font" = "%@ Font";
+
+/* Used for 'add' options within menus */
+"menu-add" = "Dzakti";
+
+/* Used to indicate a sequence of menu options that a user needs to copy. May be chained. Example: "Keyboards (1) > Enable Keyman (2)" */
+"menu-breadcrumbing" = "%1$@ > %2$@";
+
+/* Used to exit a menu without choosing an option */
+"menu-cancel" = "Kansǝl";
+
+/* Menu option that erases all previously-typed text. */
+"menu-clear-text" = "Kǝkǝrnta Text";
+
+/* Menu option that displays a list designed to help users start using the app */
+"menu-get-started" = "Badicini";
+
+/* Menu option that displays help for the app */
+"menu-help" = "Sǝr Zǝndi";
+
+/* Menu option that displays the main screen's drop-down menu */
+"menu-more" = "Dzaktǝdzǝr su";
+
+/* Menu option used to edit keyboard and dictionary settings */
+"menu-settings" = "Settings";
+
+/* Menu option that displays the iOS Share menu */
+"menu-share" = "Ndǝɦǝnta";
+
+/* Menu option that displays an embedded web browser. */
+"menu-show-browser" = "Brauza";
+
+/* Menu option used to control in-app font size. */
+"menu-text-size" = "Ngakurǝr Text";
+
+/* Used to describe the current font size */
+"text-size-label" = "Ngakurǝr Text: %i";
+
+/* Text to indicate that a user should set a toggle within iOS Settings to 'active'. */
+"toggle-to-enable" = "ʻYati ka ʻya %@";
+
+/* First option on the Get Started tutorial - Add a keyboard for your language */
+"tutorial-add-keyboard" = "Dzakǝkǝr kibod ata kǝra nyar ngɛ";
+
+/* Third option on the Get Started tutorial - Displays app help. */
+"tutorial-show-help" = "Dzaktǝr sǝr zǝndi";
+
+/* Second option on the Get Started tutorial - Set up Keyman as system-wide keyboard */
+"tutorial-system-keyboard" = "Set up Keyman as system-wide keyboard";
+
+/* Used to display app version (as in \"Version: 1.0.2\" */
+"version-label" = "Jili: %@";
diff --git a/ios/keyman/Keyman/Keyman/hia.lproj/Localizable.strings b/ios/keyman/Keyman/Keyman/hia.lproj/Localizable.strings
new file mode 100644
index 0000000000..05ba6d8976
--- /dev/null
+++ b/ios/keyman/Keyman/Keyman/hia.lproj/Localizable.strings
@@ -0,0 +1,81 @@
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-add-title" = "Mbakat Bookmark";
+
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-none" = "Haɗ bookmarks wo";
+
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-title" = "Bookmarks";
+
+/* Used to confirm a user's desire to install a package */
+"confirm-install" = "Fanta";
+
+/* The label for the toggle to stop automatically showing the "Get Started" tutorial popup. */
+"disable-get-started" = "Eh virataka maranta";
+
+/* Indicates an error opening a web page requested by a user */
+"error-opening-page" = "Ha da gunat Page wo";
+
+/* Long-form used when installing a font in order to display a language properly. */
+"font-install-description" = "Tapa fant k magat %@ plunta daideya minahagha";
+
+/* The name of the iOS Settings menu option for keyboards */
+"ios-settings-keyboards" = "Keyboards";
+
+/* The name of the iOS Settings menu option for giving the keyboard full access. (The menu entry
+underneath the app's name within the app-specific keyboard menu.) */
+"ios-settings-allow-full-access" = "Javat wativ sosaya";
+
+/* Short-form used when installing a font in order to display a language properly. */
+"language-for-font" = "%@ Font";
+
+/* Used for 'add' options within menus */
+"menu-add" = "Mbakata";
+
+/* Used to indicate a sequence of menu options that a user needs to copy. May be chained. Example: "Keyboards (1) > Enable Keyman (2)" */
+"menu-breadcrumbing" = "%1$@ > %2$@";
+
+/* Used to exit a menu without choosing an option */
+"menu-cancel" = "Jata";
+
+/* Menu option that erases all previously-typed text. */
+"menu-clear-text" = "Clear Text";
+
+/* Menu option that displays a list designed to help users start using the app */
+"menu-get-started" = "Yagha a fuɗa";
+
+/* Menu option that displays help for the app */
+"menu-help" = "Info";
+
+/* Menu option that displays the main screen's drop-down menu */
+"menu-more" = "Mbakata";
+
+/* Menu option used to edit keyboard and dictionary settings */
+"menu-settings" = "Siryata";
+
+/* Menu option that displays the iOS Share menu */
+"menu-share" = "Tiganta";
+
+/* Menu option that displays an embedded web browser. */
+"menu-show-browser" = "Browser";
+
+/* Menu option used to control in-app font size. */
+"menu-text-size" = "Text Size";
+
+/* Used to describe the current font size */
+"text-size-label" = "Text size: %i";
+
+/* Text to indicate that a user should set a toggle within iOS Settings to 'active'. */
+"toggle-to-enable" = "Javat wative %@";
+
+/* First option on the Get Started tutorial - Add a keyboard for your language */
+"tutorial-add-keyboard" = "Ambaka keyboard anga gwaɗa luwagha";
+
+/* Third option on the Get Started tutorial - Displays app help. */
+"tutorial-show-help" = "Mbakat info";
+
+/* Second option on the Get Started tutorial - Set up Keyman as system-wide keyboard */
+"tutorial-system-keyboard" = "Set up Keyman as system-wide keyboard";
+
+/* Used to display app version (as in \"Version: 1.0.2\" */
+"version-label" = "Sangabta: %@";
diff --git a/ios/keyman/Keyman/Keyman/mrt.lproj/Localizable.strings b/ios/keyman/Keyman/Keyman/mrt.lproj/Localizable.strings
new file mode 100644
index 0000000000..b47294000b
--- /dev/null
+++ b/ios/keyman/Keyman/Keyman/mrt.lproj/Localizable.strings
@@ -0,0 +1,81 @@
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-add-title" = "Mchaku Bookmark";
+
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-none" = "Bookmark aʻi mai";
+
+/* Title for the bookmarks menu within the embedded browser */
+"browser-bookmarks-title" = "Bookmarks";
+
+/* Used to confirm a user's desire to install a package */
+"confirm-install" = "Install";
+
+/* The label for the toggle to stop automatically showing the "Get Started" tutorial popup. */
+"disable-get-started" = "Asuka ga bura ncha mai";
+
+/* Indicates an error opening a web page requested by a user */
+"error-opening-page" = "Acittu pahu pagi mai";
+
+/* Long-form used when installing a font in order to display a language properly. */
+"font-install-description" = "Tsukwa Install kuga %@ nchaba kalkal akwa ca apps";
+
+/* The name of the iOS Settings menu option for keyboards */
+"ios-settings-keyboards" = "Keyboards";
+
+/* The name of the iOS Settings menu option for giving the keyboard full access. (The menu entry
+underneath the app's name within the app-specific keyboard menu.) */
+"ios-settings-allow-full-access" = "Allow Full Access";
+
+/* Short-form used when installing a font in order to display a language properly. */
+"language-for-font" = "%@ Font";
+
+/* Used for 'add' options within menus */
+"menu-add" = "Mchaku";
+
+/* Used to indicate a sequence of menu options that a user needs to copy. May be chained. Example: "Keyboards (1) > Enable Keyman (2)" */
+"menu-breadcrumbing" = "%1$@ > %2$@";
+
+/* Used to exit a menu without choosing an option */
+"menu-cancel" = "Kukulna";
+
+/* Menu option that erases all previously-typed text. */
+"menu-clear-text" = "Kukulna ndir";
+
+/* Menu option that displays a list designed to help users start using the app */
+"menu-get-started" = "Baditsini";
+
+/* Menu option that displays help for the app */
+"menu-help" = "Labar";
+
+/* Menu option that displays the main screen's drop-down menu */
+"menu-more" = "Odi";
+
+/* Menu option used to edit keyboard and dictionary settings */
+"menu-settings" = "Settings";
+
+/* Menu option that displays the iOS Share menu */
+"menu-share" = "Ntiku";
+
+/* Menu option that displays an embedded web browser. */
+"menu-show-browser" = "Browser";
+
+/* Menu option used to control in-app font size. */
+"menu-text-size" = "Nga nur ruɓutsini";
+
+/* Used to describe the current font size */
+"text-size-label" = "Nga nur ruɓutsini: %i";
+
+/* Text to indicate that a user should set a toggle within iOS Settings to 'active'. */
+"toggle-to-enable" = "Enable %@";
+
+/* First option on the Get Started tutorial - Add a keyboard for your language */
+"tutorial-add-keyboard" = "Mchaku keyboard anu ŋya ginyi";
+
+/* Third option on the Get Started tutorial - Displays app help. */
+"tutorial-show-help" = "Labar odi";
+
+/* Second option on the Get Started tutorial - Set up Keyman as system-wide keyboard */
+"tutorial-system-keyboard" = "Set up Keyman as system-wide keyboard";
+
+/* Used to display app version (as in \"Version: 1.0.2\" */
+"version-label" = "Version: %@";
diff --git a/lerna.json b/lerna.json
index 47951c5924..52890e8f37 100644
--- a/lerna.json
+++ b/lerna.json
@@ -20,5 +20,5 @@
"ts-node",
"typescript"
],
- "version": "15.0.177"
+ "version": "15.0.184"
}
diff --git a/linux/README.md b/linux/README.md
index 5e016355b0..1c670a7f87 100644
--- a/linux/README.md
+++ b/linux/README.md
@@ -97,7 +97,7 @@ Nightly and release builds upload the most recent new master build to Mon, 02 Aug 2021 18:13:58 +0200
+keyman-config (14.0.284-3) unstable; urgency=medium
+
+ * Team upload
+ * No-change rebuild against python-requests-cache 0.9.1-1
+ - The build of keyman-config 14.0.284-1 failed. Hopefully we'll be
+ more lucky this time.
+
+ -- Gunnar Hjalmarsson Wed, 19 Jan 2022 12:50:32 +0100
+
+keyman-config (14.0.284-1) unstable; urgency=medium
+
+ * New upstream release
+ * Re-release to Debian
+
+ -- Eberhard Beilharz Fri, 14 Jan 2022 18:00:21 +0100
+
keyman-config (14.0.283-2) unstable; urgency=medium
* New upstream release
diff --git a/linux/debian/upstream/metadata b/linux/debian/upstream/metadata
new file mode 100644
index 0000000000..b39284a678
--- /dev/null
+++ b/linux/debian/upstream/metadata
@@ -0,0 +1,7 @@
+Bug-Database: https://github.com/keymanapp/keyman/issues
+Bug-Submit: https://github.com/keymanapp/keyman/issues/new/choose
+Donation: https://keyman.com/donate
+FAQ: https://help.keyman.com/products/linux/current-version/common/
+Repository: https://github.com/keymanapp/keyman
+Repository-Browse: https://github.com/keymanapp/keyman
+Security-Contact: https://software.sil.org/about/contact/
diff --git a/linux/keyman-config/locale/ckl_NG.po b/linux/keyman-config/locale/ckl_NG.po
new file mode 100644
index 0000000000..8ab18a070b
--- /dev/null
+++ b/linux/keyman-config/locale/ckl_NG.po
@@ -0,0 +1,332 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: keyman\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-08-19 19:17+0200\n"
+"PO-Revision-Date: 2021-12-15 03:26\n"
+"Last-Translator: \n"
+"Language-Team: Kibaku\n"
+"Language: ckl_NG\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Crowdin-Project: keyman\n"
+"X-Crowdin-Project-ID: 386703\n"
+"X-Crowdin-Language: ckl\n"
+"X-Crowdin-File: /master/linux/keyman-config.pot\n"
+"X-Crowdin-File-ID: 504\n"
+
+#: keyman_config/__init__.py:68
+msgid "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
+msgstr "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
+
+#: keyman_config/downloadkeyboard.py:23
+msgid "Download Keyman keyboards"
+msgstr "Ka Gǝ Sǝgǝl Aka Keyman kibodyere"
+
+#: keyman_config/downloadkeyboard.py:37 keyman_config/keyboard_details.py:49
+#: keyman_config/keyboard_details.py:340 keyman_config/view_installed.py:205
+msgid "_Close"
+msgstr "_Harti"
+
+#: keyman_config/install_kmp.py:99
+msgid "You do not have permissions to install the keyboard files to the shared area /usr/local/share/keyman"
+msgstr "Gadiyaka iziniyere wɛ nǝr vu failyere nǝr kibod akwa shared area /usr/local/share/keyman"
+
+#: keyman_config/install_kmp.py:103
+msgid "You do not have permissions to install the documentation to the shared documentation area /usr/local/share/doc/keyman"
+msgstr "Gadiyaka iziniyere nǝr vu documentation alukwa viyir shared documentation /usr/local/share/doc/keyman"
+
+#: keyman_config/install_kmp.py:107
+msgid "You do not have permissions to install the font files to the shared font area /usr/local/share/fonts"
+msgstr "Gadiyaka iziniyere nǝr vu failyere nǝr font akwa viyir shared font /usr/local/share/fonts"
+
+#: keyman_config/install_kmp.py:179
+#, python-brace-format
+msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {package}"
+msgstr "install_kmp.py: error: No kmp.json or kmp.inf found in {package}"
+
+#: keyman_config/install_kmp.py:246
+#, python-brace-format
+msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}"
+msgstr "install_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}"
+
+#: keyman_config/install_window.py:54
+#, python-brace-format
+msgid "Installing keyboard/package {keyboardid}"
+msgstr "Installing keyboard/package {keyboardid}"
+
+#: keyman_config/install_window.py:72 keyman_config/install_window.py:93
+msgid "Keyboard is installed already"
+msgstr "Ndǝ kurta vu kibod"
+
+#: keyman_config/install_window.py:74
+#, python-brace-format
+msgid "The {name} keyboard is already installed at version {version}. Do you want to uninstall then reinstall it?"
+msgstr "The {name} keyboard is already installed at version {version}. Do you want to uninstall then reinstall it?"
+
+#: keyman_config/install_window.py:95
+#, python-brace-format
+msgid "The {name} keyboard is already installed with a newer version {installedversion}. Do you want to uninstall it and install the older version {version}?"
+msgstr "The {name} keyboard is already installed with a newer version {installedversion}. Do you want to uninstall it and install the older version {version}?"
+
+#: keyman_config/install_window.py:128
+msgid "Keyboard layouts: "
+msgstr "Keyboard layouts: "
+
+#: keyman_config/install_window.py:147
+msgid "Fonts: "
+msgstr "Fontyere: "
+
+#: keyman_config/install_window.py:167 keyman_config/keyboard_details.py:96
+msgid "Package version: "
+msgstr "Package version: "
+
+#: keyman_config/install_window.py:179
+msgid "Author: "
+msgstr "Author: "
+
+#: keyman_config/install_window.py:197
+msgid "Website: "
+msgstr "Websait: "
+
+#: keyman_config/install_window.py:211
+msgid "Copyright: "
+msgstr "Kopirait: "
+
+#: keyman_config/install_window.py:245
+msgid "Details"
+msgstr "Details"
+
+#: keyman_config/install_window.py:248
+msgid "README"
+msgstr "README"
+
+#: keyman_config/install_window.py:256 keyman_config/view_installed.py:200
+msgid "_Install"
+msgstr "_Vu"
+
+#: keyman_config/install_window.py:260
+msgid "_Cancel"
+msgstr "_Kansǝl"
+
+#: keyman_config/install_window.py:305
+#, python-brace-format
+msgid "Keyboard {name} installed"
+msgstr "Kibod {name} namtǝ ndǝ vu"
+
+#: keyman_config/install_window.py:310 keyman_config/install_window.py:315
+#, python-brace-format
+msgid "Keyboard {name} could not be installed."
+msgstr "Kibod {name} adita ɓui ka vudzi wɛcould not be installed."
+
+#: keyman_config/install_window.py:311
+msgid "Error Message:"
+msgstr "Sako Nǝr Su Kura Kal Kal:"
+
+#: keyman_config/install_window.py:316
+msgid "Warning Message:"
+msgstr "Saka Apǝri Su Kura Kal Kal Adai wɛ:"
+
+#: keyman_config/keyboard_details.py:37
+#, python-brace-format
+msgid "{name} keyboard"
+msgstr "{name} kibod"
+
+#: keyman_config/keyboard_details.py:53
+msgid "ERROR: Keyboard metadata is damaged.\n"
+"Please \"Uninstall\" and then \"Install\" the keyboard."
+msgstr "ERROR: Keyboard metadata is damaged.\n"
+"Please \"Uninstall\" and then \"Install\" the keyboard."
+
+#: keyman_config/keyboard_details.py:74
+msgid "Package name: "
+msgstr "Thlǝma package: "
+
+#: keyman_config/keyboard_details.py:85
+msgid "Package id: "
+msgstr "Id nǝr package: "
+
+#: keyman_config/keyboard_details.py:108
+msgid "Package description: "
+msgstr "Sǝr gǝlayere ata kǝra package: "
+
+#: keyman_config/keyboard_details.py:121
+msgid "Package author: "
+msgstr "Ndǝ tara rubwai suyere ata kǝra package: "
+
+#: keyman_config/keyboard_details.py:133
+msgid "Package copyright: "
+msgstr "Package copyright: "
+
+#: keyman_config/keyboard_details.py:174
+msgid "Keyboard filename: "
+msgstr "Thlǝma fail nǝr kibod: "
+
+#: keyman_config/keyboard_details.py:187
+msgid "Keyboard name: "
+msgstr "Thlǝma kibod: "
+
+#: keyman_config/keyboard_details.py:198
+msgid "Keyboard id: "
+msgstr "Kibod id: "
+
+#: keyman_config/keyboard_details.py:209
+msgid "Keyboard version: "
+msgstr "Jiliyir kibod: "
+
+#: keyman_config/keyboard_details.py:221
+msgid "Keyboard author: "
+msgstr "Ndǝ tara rubwai kibod: "
+
+#: keyman_config/keyboard_details.py:232
+msgid "Keyboard license: "
+msgstr "Lasǝe nǝr kibod: "
+
+#: keyman_config/keyboard_details.py:243
+msgid "Keyboard description: "
+msgstr "Sǝr gǝlayere ata kǝra eyboard d: "
+
+#: keyman_config/keyboard_details.py:334
+#, python-brace-format
+msgid "Scan this code to load this keyboard\n"
+"on another device or share online"
+msgstr "Skanba code ǝni akuya ka gǝ vu kibod\n"
+"ata divais damwa ko share online"
+
+#: keyman_config/options.py:24
+#, python-brace-format
+msgid "{packageId} Settings"
+msgstr "{packageId} Settings"
+
+#: keyman_config/view_installed.py:30
+msgid "Keyman Configuration"
+msgstr "Keyman Configuration"
+
+#: keyman_config/view_installed.py:60
+msgid "Choose a kmp file..."
+msgstr "Tsarba fail nǝr kmp..."
+
+#. i18n: file type in file selection dialog
+#: keyman_config/view_installed.py:65
+msgid "KMP files"
+msgstr "Failyere nǝr KMP"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:141
+msgid "Icon"
+msgstr "Aikon"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:145
+msgid "Name"
+msgstr "Thlǝmɛ"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:148
+msgid "Version"
+msgstr "Version"
+
+#: keyman_config/view_installed.py:161
+msgid "_Uninstall"
+msgstr "_Kǝlba ka ɗalba"
+
+#: keyman_config/view_installed.py:162 keyman_config/view_installed.py:304
+msgid "Uninstall keyboard"
+msgstr "Kǝlba ka ɗalba kibod"
+
+#: keyman_config/view_installed.py:167
+msgid "_About"
+msgstr "_Ata kǝra"
+
+#: keyman_config/view_installed.py:168 keyman_config/view_installed.py:306
+msgid "About keyboard"
+msgstr "Ata kǝra kibod"
+
+#: keyman_config/view_installed.py:173
+msgid "_Help"
+msgstr "_Dlarɛ"
+
+#: keyman_config/view_installed.py:174 keyman_config/view_installed.py:305
+msgid "Help for keyboard"
+msgstr "Dlarɛ kadǝbar kibod"
+
+#: keyman_config/view_installed.py:179
+msgid "_Options"
+msgstr "_Options"
+
+#: keyman_config/view_installed.py:180 keyman_config/view_installed.py:307
+msgid "Settings for keyboard"
+msgstr "Settingyere nǝr kibod"
+
+#: keyman_config/view_installed.py:190
+msgid "_Refresh"
+msgstr "_Refresh"
+
+#: keyman_config/view_installed.py:191
+msgid "Refresh keyboard list"
+msgstr "Refresh keyboard list"
+
+#: keyman_config/view_installed.py:195
+msgid "_Download"
+msgstr "_Dawnload"
+
+#: keyman_config/view_installed.py:196
+msgid "Download and install a keyboard from the Keyman website"
+msgstr "Download ba vu kibod nam akwa websait nǝr Keyman"
+
+#: keyman_config/view_installed.py:201
+msgid "Install a keyboard from a file"
+msgstr "Vu kibod namtǝ gǝ kǝlba akwa fail"
+
+#: keyman_config/view_installed.py:206
+msgid "Close window"
+msgstr "Harti window"
+
+#: keyman_config/view_installed.py:278
+#, python-brace-format
+msgid "Uninstall keyboard {package}"
+msgstr "Kǝlba ka ɗalba kibod{package}"
+
+#: keyman_config/view_installed.py:280
+#, python-brace-format
+msgid "Help for keyboard {package}"
+msgstr "Dlarɛ tubwar kibod {package}"
+
+#: keyman_config/view_installed.py:282
+#, python-brace-format
+msgid "About keyboard {package}"
+msgstr "Ata kǝra kibod {package}"
+
+#: keyman_config/view_installed.py:284
+#, python-brace-format
+msgid "Settings for keyboard {package}"
+msgstr "Settingyere nǝr kibod {package}"
+
+#: keyman_config/view_installed.py:349
+msgid "Uninstall keyboard package?"
+msgstr "Uninstall keyboard package?"
+
+#: keyman_config/view_installed.py:351
+#, python-brace-format
+msgid "Are you sure that you want to uninstall the {keyboard} keyboard and its fonts?"
+msgstr "Gǝ tǝmacini ga da bara kǝlba ka ɗalba {keyboard} kibod kǝka fontyarariyere?"
+
+#: keyman_config/welcome.py:22
+#, python-brace-format
+msgid "{name} installed"
+msgstr "{name} namtǝ ndǝ vu"
+
+#: keyman_config/welcome.py:40
+msgid "Open in _Web browser"
+msgstr "Mburnta akwa _Web browser"
+
+#: keyman_config/welcome.py:42
+msgid "Open in the default web browser to do things like printing"
+msgstr "Mburnta akwa default web browser akuya ka gǝ ʻya suyere apa printing"
+
+#: keyman_config/welcome.py:45
+msgid "_OK"
+msgstr "_Kal kal"
+
diff --git a/linux/keyman-config/locale/hia_NG.po b/linux/keyman-config/locale/hia_NG.po
new file mode 100644
index 0000000000..debc6746a7
--- /dev/null
+++ b/linux/keyman-config/locale/hia_NG.po
@@ -0,0 +1,332 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: keyman\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-08-19 19:17+0200\n"
+"PO-Revision-Date: 2021-12-15 08:42\n"
+"Last-Translator: \n"
+"Language-Team: Waha (Lamang)\n"
+"Language: hia_NG\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==0 ? 0 : n%10==1 && n%100!=11 ? 1 : 2);\n"
+"X-Crowdin-Project: keyman\n"
+"X-Crowdin-Project-ID: 386703\n"
+"X-Crowdin-Language: hia\n"
+"X-Crowdin-File: /master/linux/keyman-config.pot\n"
+"X-Crowdin-File-ID: 504\n"
+
+#: keyman_config/__init__.py:68
+msgid "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
+msgstr "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
+
+#: keyman_config/downloadkeyboard.py:23
+msgid "Download Keyman keyboards"
+msgstr "Sangat Keyman keyboards"
+
+#: keyman_config/downloadkeyboard.py:37 keyman_config/keyboard_details.py:49
+#: keyman_config/keyboard_details.py:340 keyman_config/view_installed.py:205
+msgid "_Close"
+msgstr "_Funta"
+
+#: keyman_config/install_kmp.py:99
+msgid "You do not have permissions to install the keyboard files to the shared area /usr/local/share/keyman"
+msgstr "Haka nda wativa fant keyboard files tabgunda da tugutalu /usr/local/share/keyman"
+
+#: keyman_config/install_kmp.py:103
+msgid "You do not have permissions to install the documentation to the shared documentation area /usr/local/share/doc/keyman"
+msgstr "Haka nda wativa fant takardaha kor t gwaɗa anga tuguta takarda kor gwaɗa tabga takarda ngane /usr/local/share/doc/keyman"
+
+#: keyman_config/install_kmp.py:107
+msgid "You do not have permissions to install the font files to the shared font area /usr/local/share/fonts"
+msgstr "Haka nda wativa fant font files ka tuguta tabga font area wo /usr/local/share/fonts"
+
+#: keyman_config/install_kmp.py:179
+#, python-brace-format
+msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {package}"
+msgstr "anfat_kmp.py: error: No kmp.json or kmp.inf found in {package}"
+
+#: keyman_config/install_kmp.py:246
+#, python-brace-format
+msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}"
+msgstr "anfat_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}"
+
+#: keyman_config/install_window.py:54
+#, python-brace-format
+msgid "Installing keyboard/package {keyboardid}"
+msgstr "Fant keyboard/package {keyboardid}"
+
+#: keyman_config/install_window.py:72 keyman_config/install_window.py:93
+msgid "Keyboard is installed already"
+msgstr "Keyboard nganana puta putal fanta"
+
+#: keyman_config/install_window.py:74
+#, python-brace-format
+msgid "The {name} keyboard is already installed at version {version}. Do you want to uninstall then reinstall it?"
+msgstr "The {name} keyboard nganana puta putal fanta t version {version}. Dow ka k thlahat fanta guka virata fantare?"
+
+#: keyman_config/install_window.py:95
+#, python-brace-format
+msgid "The {name} keyboard is already installed with a newer version {installedversion}. Do you want to uninstall it and install the older version {version}?"
+msgstr "The {name} keyboard nganana puta putal fanta nda wuliwa version {installedversion}. Ɗow ka k thlahat fanta nda fant nguzaka version {version}?"
+
+#: keyman_config/install_window.py:128
+msgid "Keyboard layouts: "
+msgstr "Keyboard layouts: "
+
+#: keyman_config/install_window.py:147
+msgid "Fonts: "
+msgstr "Fonts: "
+
+#: keyman_config/install_window.py:167 keyman_config/keyboard_details.py:96
+msgid "Package version: "
+msgstr "Package version: "
+
+#: keyman_config/install_window.py:179
+msgid "Author: "
+msgstr "Dada vindata: "
+
+#: keyman_config/install_window.py:197
+msgid "Website: "
+msgstr "Website: "
+
+#: keyman_config/install_window.py:211
+msgid "Copyright: "
+msgstr "Magata daideya man ndunda sa magalo: "
+
+#: keyman_config/install_window.py:245
+msgid "Details"
+msgstr "An talan tala"
+
+#: keyman_config/install_window.py:248
+msgid "README"
+msgstr "I JANGA"
+
+#: keyman_config/install_window.py:256 keyman_config/view_installed.py:200
+msgid "_Install"
+msgstr "_Fanta"
+
+#: keyman_config/install_window.py:260
+msgid "_Cancel"
+msgstr "_Jata"
+
+#: keyman_config/install_window.py:305
+#, python-brace-format
+msgid "Keyboard {name} installed"
+msgstr "Keyboard {name} fan falo"
+
+#: keyman_config/install_window.py:310 keyman_config/install_window.py:315
+#, python-brace-format
+msgid "Keyboard {name} could not be installed."
+msgstr "Keyboard {name} fa buwo."
+
+#: keyman_config/install_window.py:311
+msgid "Error Message:"
+msgstr "Kuskura habar:"
+
+#: keyman_config/install_window.py:316
+msgid "Warning Message:"
+msgstr "Habara ndoyo:"
+
+#: keyman_config/keyboard_details.py:37
+#, python-brace-format
+msgid "{name} keyboard"
+msgstr "{name} keyboard"
+
+#: keyman_config/keyboard_details.py:53
+msgid "ERROR: Keyboard metadata is damaged.\n"
+"Please \"Uninstall\" and then \"Install\" the keyboard."
+msgstr "KUSKURE: Keyboard metadata na gayu gaya.\n"
+"Gamsa \"Avathla\" nda guleng \"anfa\" t keyboard ngane."
+
+#: keyman_config/keyboard_details.py:74
+msgid "Package name: "
+msgstr "Zira package: "
+
+#: keyman_config/keyboard_details.py:85
+msgid "Package id: "
+msgstr "Package id: "
+
+#: keyman_config/keyboard_details.py:108
+msgid "Package description: "
+msgstr "Package description: "
+
+#: keyman_config/keyboard_details.py:121
+msgid "Package author: "
+msgstr "Package dada vindata: "
+
+#: keyman_config/keyboard_details.py:133
+msgid "Package copyright: "
+msgstr "Package copyright: "
+
+#: keyman_config/keyboard_details.py:174
+msgid "Keyboard filename: "
+msgstr "Keyboard filename: "
+
+#: keyman_config/keyboard_details.py:187
+msgid "Keyboard name: "
+msgstr "Zira keyboard: "
+
+#: keyman_config/keyboard_details.py:198
+msgid "Keyboard id: "
+msgstr "Keyboard id: "
+
+#: keyman_config/keyboard_details.py:209
+msgid "Keyboard version: "
+msgstr "Keyboard version: "
+
+#: keyman_config/keyboard_details.py:221
+msgid "Keyboard author: "
+msgstr "Keyboard dada vindata: "
+
+#: keyman_config/keyboard_details.py:232
+msgid "Keyboard license: "
+msgstr "Keyboard license: "
+
+#: keyman_config/keyboard_details.py:243
+msgid "Keyboard description: "
+msgstr "Keyboard description: "
+
+#: keyman_config/keyboard_details.py:334
+#, python-brace-format
+msgid "Scan this code to load this keyboard\n"
+"on another device or share online"
+msgstr "Kla fota nana code na k klaft tana keyboard na taghan device sakwiɗi ko\n"
+" share online"
+
+#: keyman_config/options.py:24
+#, python-brace-format
+msgid "{packageId} Settings"
+msgstr "{packageId} Settings"
+
+#: keyman_config/view_installed.py:30
+msgid "Keyman Configuration"
+msgstr "Keyman Configuration"
+
+#: keyman_config/view_installed.py:60
+msgid "Choose a kmp file..."
+msgstr "Abkla t kmp file..."
+
+#. i18n: file type in file selection dialog
+#: keyman_config/view_installed.py:65
+msgid "KMP files"
+msgstr "KMP files"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:141
+msgid "Icon"
+msgstr "Icon"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:145
+msgid "Name"
+msgstr "Ziro"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:148
+msgid "Version"
+msgstr "Version"
+
+#: keyman_config/view_installed.py:161
+msgid "_Uninstall"
+msgstr "_Fan bol wo"
+
+#: keyman_config/view_installed.py:162 keyman_config/view_installed.py:304
+msgid "Uninstall keyboard"
+msgstr "Keyboard kol fantalo"
+
+#: keyman_config/view_installed.py:167
+msgid "_About"
+msgstr "_Kor tina man tundu ko tina"
+
+#: keyman_config/view_installed.py:168 keyman_config/view_installed.py:306
+msgid "About keyboard"
+msgstr "Gwaɗa keyboard"
+
+#: keyman_config/view_installed.py:173
+msgid "_Help"
+msgstr "_Tamako"
+
+#: keyman_config/view_installed.py:174 keyman_config/view_installed.py:305
+msgid "Help for keyboard"
+msgstr "Tamoko anga keyboard"
+
+#: keyman_config/view_installed.py:179
+msgid "_Options"
+msgstr "_Inunda ɗowƙa k mogo"
+
+#: keyman_config/view_installed.py:180 keyman_config/view_installed.py:307
+msgid "Settings for keyboard"
+msgstr "Settings for keyboard"
+
+#: keyman_config/view_installed.py:190
+msgid "_Refresh"
+msgstr "_Virata gunata"
+
+#: keyman_config/view_installed.py:191
+msgid "Refresh keyboard list"
+msgstr "Virata gunat keyboard list"
+
+#: keyman_config/view_installed.py:195
+msgid "_Download"
+msgstr "_Sangata"
+
+#: keyman_config/view_installed.py:196
+msgid "Download and install a keyboard from the Keyman website"
+msgstr "Angasa guka fant keyboard avla Keyman website"
+
+#: keyman_config/view_installed.py:201
+msgid "Install a keyboard from a file"
+msgstr "An fat keyboard avla file"
+
+#: keyman_config/view_installed.py:206
+msgid "Close window"
+msgstr "Unfa tina sma"
+
+#: keyman_config/view_installed.py:278
+#, python-brace-format
+msgid "Uninstall keyboard {package}"
+msgstr "E funatka t keyboard {package}"
+
+#: keyman_config/view_installed.py:280
+#, python-brace-format
+msgid "Help for keyboard {package}"
+msgstr "Tamoko anga keyboard {package}"
+
+#: keyman_config/view_installed.py:282
+#, python-brace-format
+msgid "About keyboard {package}"
+msgstr "Gwaɗa keyboard {package}"
+
+#: keyman_config/view_installed.py:284
+#, python-brace-format
+msgid "Settings for keyboard {package}"
+msgstr "Settings for keyboard {package}"
+
+#: keyman_config/view_installed.py:349
+msgid "Uninstall keyboard package?"
+msgstr "E fantaka t keyboard package?"
+
+#: keyman_config/view_installed.py:351
+#, python-brace-format
+msgid "Are you sure that you want to uninstall the {keyboard} keyboard and its fonts?"
+msgstr "Tabata tabatakana ɗow k thlavat ka fant {keyboard} keyboard nda fonts ni?"
+
+#: keyman_config/welcome.py:22
+#, python-brace-format
+msgid "{name} installed"
+msgstr "{name} falo"
+
+#: keyman_config/welcome.py:40
+msgid "Open in _Web browser"
+msgstr "Gunat _Web browser"
+
+#: keyman_config/welcome.py:42
+msgid "Open in the default web browser to do things like printing"
+msgstr "Gunat mina gayuta web browser k magat tina man li vindo"
+
+#: keyman_config/welcome.py:45
+msgid "_OK"
+msgstr "_Muvaya"
+
diff --git a/linux/keyman-config/locale/mrt_NG.po b/linux/keyman-config/locale/mrt_NG.po
new file mode 100644
index 0000000000..5a24cca245
--- /dev/null
+++ b/linux/keyman-config/locale/mrt_NG.po
@@ -0,0 +1,331 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: keyman\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-08-19 19:17+0200\n"
+"PO-Revision-Date: 2021-12-15 05:44\n"
+"Last-Translator: \n"
+"Language-Team: Marghi\n"
+"Language: mrt_NG\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Crowdin-Project: keyman\n"
+"X-Crowdin-Project-ID: 386703\n"
+"X-Crowdin-Language: mrt\n"
+"X-Crowdin-File: /master/linux/keyman-config.pot\n"
+"X-Crowdin-File-ID: 504\n"
+
+#: keyman_config/__init__.py:68
+msgid "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
+msgstr "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
+
+#: keyman_config/downloadkeyboard.py:23
+msgid "Download Keyman keyboards"
+msgstr "Download Keyman keyboards"
+
+#: keyman_config/downloadkeyboard.py:37 keyman_config/keyboard_details.py:49
+#: keyman_config/keyboard_details.py:340 keyman_config/view_installed.py:205
+msgid "_Close"
+msgstr "_Ghaɗu"
+
+#: keyman_config/install_kmp.py:99
+msgid "You do not have permissions to install the keyboard files to the shared area /usr/local/share/keyman"
+msgstr "Mji a ngeri kuga installi file yer nur keyboard anu ivi dun mji ga ntiku mai /usr/local/share/keyman"
+
+#: keyman_config/install_kmp.py:103
+msgid "You do not have permissions to install the documentation to the shared documentation area /usr/local/share/doc/keyman"
+msgstr "Mji a ngeri kuga installi ruɓutsini anu ivi du mji vur iu thlir mai/usr/local/share/doc/keyman"
+
+#: keyman_config/install_kmp.py:107
+msgid "You do not have permissions to install the font files to the shared font area /usr/local/share/fonts"
+msgstr "Mji a ngeri kuga installi fayel nur font mai anu ividu mji vur iu thlir aga font /usr/local/share/fonts"
+
+#: keyman_config/install_kmp.py:179
+#, python-brace-format
+msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {package}"
+msgstr "install_kmp.py: error: No kmp.json or kmp.inf found in {package}"
+
+#: keyman_config/install_kmp.py:246
+#, python-brace-format
+msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}"
+msgstr "install_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}"
+
+#: keyman_config/install_window.py:54
+#, python-brace-format
+msgid "Installing keyboard/package {keyboardid}"
+msgstr "Installing keyboard/package {keyboardid}"
+
+#: keyman_config/install_window.py:72 keyman_config/install_window.py:93
+msgid "Keyboard is installed already"
+msgstr "Akuya installed keyboard"
+
+#: keyman_config/install_window.py:74
+#, python-brace-format
+msgid "The {name} keyboard is already installed at version {version}. Do you want to uninstall then reinstall it?"
+msgstr "{name} keyboard akuya installed version {version} ari. Nagu ayu ga bura uninstall baɗa tsu reinstall ya?"
+
+#: keyman_config/install_window.py:95
+#, python-brace-format
+msgid "The {name} keyboard is already installed with a newer version {installedversion}. Do you want to uninstall it and install the older version {version}?"
+msgstr "{name} keyboard mji akuya installed aga version bilin {installedversion}. Nagu ayu ga uninstall baɗa install version {version} nur dang ya?"
+
+#: keyman_config/install_window.py:128
+msgid "Keyboard layouts: "
+msgstr "Keyboard layouts: "
+
+#: keyman_config/install_window.py:147
+msgid "Fonts: "
+msgstr "Fonts: "
+
+#: keyman_config/install_window.py:167 keyman_config/keyboard_details.py:96
+msgid "Package version: "
+msgstr "Package version: "
+
+#: keyman_config/install_window.py:179
+msgid "Author: "
+msgstr "Author: "
+
+#: keyman_config/install_window.py:197
+msgid "Website: "
+msgstr "Website: "
+
+#: keyman_config/install_window.py:211
+msgid "Copyright: "
+msgstr "Copyright: "
+
+#: keyman_config/install_window.py:245
+msgid "Details"
+msgstr "Labar yer"
+
+#: keyman_config/install_window.py:248
+msgid "README"
+msgstr "README"
+
+#: keyman_config/install_window.py:256 keyman_config/view_installed.py:200
+msgid "_Install"
+msgstr "_Install"
+
+#: keyman_config/install_window.py:260
+msgid "_Cancel"
+msgstr "_Kukulna"
+
+#: keyman_config/install_window.py:305
+#, python-brace-format
+msgid "Keyboard {name} installed"
+msgstr "{name} keyboard dun mji ga installed"
+
+#: keyman_config/install_window.py:310 keyman_config/install_window.py:315
+#, python-brace-format
+msgid "Keyboard {name} could not be installed."
+msgstr "Mji acittu installed Keyboard {name} mai."
+
+#: keyman_config/install_window.py:311
+msgid "Error Message:"
+msgstr "Error Message:"
+
+#: keyman_config/install_window.py:316
+msgid "Warning Message:"
+msgstr "Warning Message:"
+
+#: keyman_config/keyboard_details.py:37
+#, python-brace-format
+msgid "{name} keyboard"
+msgstr "{name} keyboard"
+
+#: keyman_config/keyboard_details.py:53
+msgid "ERROR: Keyboard metadata is damaged.\n"
+"Please \"Uninstall\" and then \"Install\" the keyboard."
+msgstr "ERROR: Keyboard metadata naja ga mdzu.\n"
+"Manki \"Uninstall\" baɗa tsu kuga \"Install\" keyboard ari."
+
+#: keyman_config/keyboard_details.py:74
+msgid "Package name: "
+msgstr "Thlimu Package: "
+
+#: keyman_config/keyboard_details.py:85
+msgid "Package id: "
+msgstr "Id nur Package: "
+
+#: keyman_config/keyboard_details.py:108
+msgid "Package description: "
+msgstr "Sur caba Package: "
+
+#: keyman_config/keyboard_details.py:121
+msgid "Package author: "
+msgstr "Package author: "
+
+#: keyman_config/keyboard_details.py:133
+msgid "Package copyright: "
+msgstr "Package copyright: "
+
+#: keyman_config/keyboard_details.py:174
+msgid "Keyboard filename: "
+msgstr "Keyboard filename: "
+
+#: keyman_config/keyboard_details.py:187
+msgid "Keyboard name: "
+msgstr "Thlimun Keyboard: "
+
+#: keyman_config/keyboard_details.py:198
+msgid "Keyboard id: "
+msgstr "Id nur Keyboard: "
+
+#: keyman_config/keyboard_details.py:209
+msgid "Keyboard version: "
+msgstr "Keyboard version: "
+
+#: keyman_config/keyboard_details.py:221
+msgid "Keyboard author: "
+msgstr "Keyboard author: "
+
+#: keyman_config/keyboard_details.py:232
+msgid "Keyboard license: "
+msgstr "Lasisi nur Keyboard: "
+
+#: keyman_config/keyboard_details.py:243
+msgid "Keyboard description: "
+msgstr "Sur caba Keyboard: "
+
+#: keyman_config/keyboard_details.py:334
+#, python-brace-format
+msgid "Scan this code to load this keyboard\n"
+"on another device or share online"
+msgstr "Kuga iu scan nur code ku ga fia keyboard arkra su nagum akiya mai share online"
+
+#: keyman_config/options.py:24
+#, python-brace-format
+msgid "{packageId} Settings"
+msgstr "{packageId} Settings"
+
+#: keyman_config/view_installed.py:30
+msgid "Keyman Configuration"
+msgstr "Keyman Configuration"
+
+#: keyman_config/view_installed.py:60
+msgid "Choose a kmp file..."
+msgstr "Caɗu kmp file..."
+
+#. i18n: file type in file selection dialog
+#: keyman_config/view_installed.py:65
+msgid "KMP files"
+msgstr "KMP file yer"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:141
+msgid "Icon"
+msgstr "Icon"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:145
+msgid "Name"
+msgstr "Thlimu"
+
+#. i18n: column header in table displaying installed keyboards
+#: keyman_config/view_installed.py:148
+msgid "Version"
+msgstr "Version"
+
+#: keyman_config/view_installed.py:161
+msgid "_Uninstall"
+msgstr "_Uninstall"
+
+#: keyman_config/view_installed.py:162 keyman_config/view_installed.py:304
+msgid "Uninstall keyboard"
+msgstr "Uninstall keyboard"
+
+#: keyman_config/view_installed.py:167
+msgid "_About"
+msgstr "_Arkra"
+
+#: keyman_config/view_installed.py:168 keyman_config/view_installed.py:306
+msgid "About keyboard"
+msgstr "Arkra keyboard"
+
+#: keyman_config/view_installed.py:173
+msgid "_Help"
+msgstr "_Ɓa"
+
+#: keyman_config/view_installed.py:174 keyman_config/view_installed.py:305
+msgid "Help for keyboard"
+msgstr "Ɓa anu keyboard"
+
+#: keyman_config/view_installed.py:179
+msgid "_Options"
+msgstr "_Nagum yer"
+
+#: keyman_config/view_installed.py:180 keyman_config/view_installed.py:307
+msgid "Settings for keyboard"
+msgstr "Settings anu keyboard"
+
+#: keyman_config/view_installed.py:190
+msgid "_Refresh"
+msgstr "_Refresh"
+
+#: keyman_config/view_installed.py:191
+msgid "Refresh keyboard list"
+msgstr "Refresh keyboard list"
+
+#: keyman_config/view_installed.py:195
+msgid "_Download"
+msgstr "_Download"
+
+#: keyman_config/view_installed.py:196
+msgid "Download and install a keyboard from the Keyman website"
+msgstr "Kuga iu download baɗa install nur keyboard ara Keyman website"
+
+#: keyman_config/view_installed.py:201
+msgid "Install a keyboard from a file"
+msgstr "Install keyboard ara file"
+
+#: keyman_config/view_installed.py:206
+msgid "Close window"
+msgstr "Ghaɗu window"
+
+#: keyman_config/view_installed.py:278
+#, python-brace-format
+msgid "Uninstall keyboard {package}"
+msgstr "Uninstall keyboard {package}"
+
+#: keyman_config/view_installed.py:280
+#, python-brace-format
+msgid "Help for keyboard {package}"
+msgstr "Ba anu keyboard {package}"
+
+#: keyman_config/view_installed.py:282
+#, python-brace-format
+msgid "About keyboard {package}"
+msgstr "Arkra keyboard {package}"
+
+#: keyman_config/view_installed.py:284
+#, python-brace-format
+msgid "Settings for keyboard {package}"
+msgstr "Settings anu keyboard {package}"
+
+#: keyman_config/view_installed.py:349
+msgid "Uninstall keyboard package?"
+msgstr "Uninstall keyboard package?"
+
+#: keyman_config/view_installed.py:351
+#, python-brace-format
+msgid "Are you sure that you want to uninstall the {keyboard} keyboard and its fonts?"
+msgstr "Nagu a tabidna aburi nagu ayu ga uninstall keyboard {keyboard} baɗa fonts ya?"
+
+#: keyman_config/welcome.py:22
+#, python-brace-format
+msgid "{name} installed"
+msgstr "{name} installed"
+
+#: keyman_config/welcome.py:40
+msgid "Open in _Web browser"
+msgstr "Pahu akwa _Web browser"
+
+#: keyman_config/welcome.py:42
+msgid "Open in the default web browser to do things like printing"
+msgstr "Pahu akwa default web browser ma nagu ayu ga iu su nagum"
+
+#: keyman_config/welcome.py:45
+msgid "_OK"
+msgstr "_OK"
+
diff --git a/linux/legacy/ibus-kmfl/debian/changelog b/linux/legacy/ibus-kmfl/debian/changelog
index 9dbfc77af8..0706b3e0f6 100644
--- a/linux/legacy/ibus-kmfl/debian/changelog
+++ b/linux/legacy/ibus-kmfl/debian/changelog
@@ -1,3 +1,10 @@
+ibus-kmfl (14.0.284-1) unstable; urgency=medium
+
+ * New upstream release
+ * Re-release to Debian
+
+ -- Eberhard Beilharz Fri, 14 Jan 2022 18:00:13 +0100
+
ibus-kmfl (14.0.283-2) unstable; urgency=medium
* New upstream release
diff --git a/linux/legacy/kmflcomp/debian/changelog b/linux/legacy/kmflcomp/debian/changelog
index 21d5ff5bab..e4f188fe5d 100644
--- a/linux/legacy/kmflcomp/debian/changelog
+++ b/linux/legacy/kmflcomp/debian/changelog
@@ -1,3 +1,10 @@
+kmflcomp (14.0.284-1) unstable; urgency=medium
+
+ * New upstream release
+ * Re-release to Debian
+
+ -- Eberhard Beilharz Fri, 14 Jan 2022 17:59:57 +0100
+
kmflcomp (14.0.283-2) unstable; urgency=medium
* New upstream release
@@ -150,7 +157,7 @@ kmflcomp (0.9.2-1) unstable; urgency=low
* Replace UTF Conversion library with a GPLed implementation
* add version and usage message to kmflcomp
- -- Doug Rintoul Thu, 02 Mar 2006 11:10:00 +0800
+ -- Doug Rintoul Thu, 02 Mar 2006 11:10:00 +0800
kmflcomp (0.9.1-1) unstable; urgency=low
@@ -158,22 +165,22 @@ kmflcomp (0.9.1-1) unstable; urgency=low
* fix bug when compile a keyboard with Non UTF upper ANSI characters
* AMD64 fixes
- -- Doug Rintoul Tue, 02 Feb 2006 11:40:00 +0800
+ -- Doug Rintoul Tue, 02 Feb 2006 11:40:00 +0800
kmflcomp (0.9-1) unstable; urgency=low
* fix shift key problem
- -- Doug Rintoul Tue, 30 Aug 2005 11:20:00 +0800
+ -- Doug Rintoul Tue, 30 Aug 2005 11:20:00 +0800
kmflcomp (0.8-1) unstable; urgency=low
* Add full virtual key support
- -- Doug Rintoul Mon, 04 Jul 2005 11:20:00 +0800
+ -- Doug Rintoul Mon, 04 Jul 2005 11:20:00 +0800
kmflcomp (0.7-1) unstable; urgency=low
* first debian release
- -- Doug Rintoul Mon, 21 Jun 2005 19:57:17 +0800
+ -- Doug Rintoul Mon, 21 Jun 2005 19:57:17 +0800
diff --git a/linux/legacy/libkmfl/debian/changelog b/linux/legacy/libkmfl/debian/changelog
index 5026d3ca44..64a9bf29f0 100644
--- a/linux/legacy/libkmfl/debian/changelog
+++ b/linux/legacy/libkmfl/debian/changelog
@@ -1,3 +1,10 @@
+libkmfl (14.0.284-1) unstable; urgency=medium
+
+ * New upstream release
+ * Re-release to Debian
+
+ -- Eberhard Beilharz Fri, 14 Jan 2022 18:00:05 +0100
+
libkmfl (14.0.283-2) unstable; urgency=medium
* New upstream release
@@ -126,30 +133,30 @@ libkmfl (0.9.2-1) unstable; urgency=low
* Replace UTF Conversion library with a GPLed implementation
* fix any/index bug
- -- Doug Rintoul Thu, 02 Mar 2006 11:10:00 +0800
+ -- Doug Rintoul Thu, 02 Mar 2006 11:10:00 +0800
libkmfl (0.9.1-1) unstable; urgency=low
* further fix for the shift key problem
* AMD64 fixes
- -- Doug Rintoul Wed, 12 Oct 2005 09:45:00 +0800
+ -- Doug Rintoul Wed, 12 Oct 2005 09:45:00 +0800
libkmfl (0.9-1) unstable; urgency=low
* fix shift key problem
- -- Doug Rintoul Tue, 30 Aug 2005 11:20:00 +0800
+ -- Doug Rintoul Tue, 30 Aug 2005 11:20:00 +0800
libkmfl (0.8-1) unstable; urgency=low
* Add full virtual key support
- -- Doug Rintoul Mon, 04 Jul 2005 11:20:00 +0800
+ -- Doug Rintoul Mon, 04 Jul 2005 11:20:00 +0800
libkmfl (0.7-1) unstable; urgency=low
* first debian release
- -- Doug Rintoul Mon, 21 Jun 2005 19:57:17 +0800
+ -- Doug Rintoul Mon, 21 Jun 2005 19:57:17 +0800
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/hia.lproj/KMAboutWindowController.strings b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/hia.lproj/KMAboutWindowController.strings
new file mode 100644
index 0000000000..458db75fc5
--- /dev/null
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/hia.lproj/KMAboutWindowController.strings
@@ -0,0 +1,8 @@
+/* button text to close the About window */
+"Kab-Up-fYH.title" = "Funta";
+
+/* text of link to the license agreement */
+"hYC-Bx-aoP.title" = "Takarda yardata";
+
+/* button text to open Configuration window */
+"vkh-b5-vO7.title" = "Configuration...";
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/km.lproj/KMAboutWindowController.strings b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/km.lproj/KMAboutWindowController.strings
index 436e9eed41..2c0d970770 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/km.lproj/KMAboutWindowController.strings
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/km.lproj/KMAboutWindowController.strings
@@ -1,9 +1,9 @@
-/* Class = "NSButtonCell"; title = "Close"; ObjectID = "Kab-Up-fYH"; */
+/* button text to close the About window */
"Kab-Up-fYH.title" = "បិទ";
-/* Class = "NSButtonCell"; title = "License Agreement"; ObjectID = "hYC-Bx-aoP"; */
+/* text of link to the license agreement */
"hYC-Bx-aoP.title" = "កិច្ចព្រមព្រៀងអាជ្ញាបណ្ណ";
-/* Class = "NSButtonCell"; title = "Configuration"; ObjectID = "vkh-b5-vO7"; */
+/* button text to open Configuration window */
"vkh-b5-vO7.title" = "ការកំណត់រចនាសម្ព័ន្ធ";
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/en.lproj/preferences.strings b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/en.lproj/preferences.strings
index 9dcd956516..a950d9fdec 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/en.lproj/preferences.strings
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/en.lproj/preferences.strings
@@ -5,7 +5,7 @@
/* Checkbox text to enable verbose Console logging */
"7J6-zy-R20.title" = "Use verbose Console logging";
-/* Support buton text */
+/* Support button text */
"93O-x6-RLF.label" = "Support";
/* Download Keyboard button text */
@@ -17,8 +17,8 @@
/* button text to go back to previous page */
"JOK-JV-n8w.title" = "Back";
-/* Class = "NSTabViewItem"; label = "Keyboard Layouts"; ObjectID = "MPN-9N-wWc"; */
-"MPN-9N-wWc.label" = "Keyboard Layouts";
+/* Keyboards button text */
+"MPN-9N-wWc.label" = "Keyboards";
/* text to explain verbose Console logging option */
"MrI-GM-7d6.title" = "When the verbose logging option is on, Keyman will log actions that might help Keyman Support diagnose a problem. The Console program can be used to see a log of messages from Keyman. In Console, filter to show all messages from the \"Keyman\" process. This log can be exported and sent to Keyman support if needed.";
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/hia.lproj/preferences.strings b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/hia.lproj/preferences.strings
new file mode 100644
index 0000000000..f2562a250d
--- /dev/null
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/hia.lproj/preferences.strings
@@ -0,0 +1,38 @@
+/* Checkbox text to always show on-screen keyboard */
+"4UX-80-0Vo.title" = "Ko ngawa an marat-screen keyboard";
+
+/* Checkbox text to enable verbose Console logging */
+"7J6-zy-R20.title" = "Maga thlina nda verbose Console logging";
+
+/* Support buton text */
+"93O-x6-RLF.label" = "Fanast jivo";
+
+/* Download Keyboard button text */
+"CTw-kf-WNS.title" = "Anga klagat Keyboard...";
+
+/* Keyman Configuration window title */
+"F0z-JX-Cv5.title" = "Keyman mrata";
+
+/* button text to go back to previous page */
+"JOK-JV-n8w.title" = "Uhili";
+
+/* Class = "NSTabViewItem"; label = "Keyboard Layouts"; ObjectID = "MPN-9N-wWc"; */
+"MPN-9N-wWc.label" = "Keyboard Layouts";
+
+/* text to explain verbose Console logging option */
+"MrI-GM-7d6.title" = "Vita verbose logging option na tadiya, Keyman da fant tinahunda da tamaka Keyman fanast jiv ina ɓilafta. Console program na da mogt thlina fant habarha javal avla Keyman. In Console, filter da marant habarha sma avla \"Keyman\" process. Nana fantanana da tsighapta jeb anga Keyman fanast jiv vita ɗowlo.";
+
+/* button text to move forward to the next page */
+"eXr-8V-h1g.title" = "Langabta t kima";
+
+/* button text to return to the home help page */
+"fXS-aC-CMH.title" = "Higa";
+
+/* Options button text */
+"frd-No-seV.label" = "Inahunda ɗowal k mogo";
+
+/* Installed Keyboard column heading */
+"jex-Nd-Qzg.headerCell.title" = "Fant Keyboard";
+
+/* Verbose logging tooltip text */
+"uWx-3J-U0D.ibShadowedToolTip" = "A gunatana vita hahaɗka nda ina damaɗata nda musaman keyboard ko nda Keyman sma sma.";
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/km.lproj/preferences.strings b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/km.lproj/preferences.strings
index 739c243913..abd999c242 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/km.lproj/preferences.strings
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/km.lproj/preferences.strings
@@ -1,39 +1,39 @@
-/* Class = "NSButtonCell"; title = "Always show on-screen keyboard"; ObjectID = "4UX-80-0Vo"; */
+/* Checkbox text to always show on-screen keyboard */
"4UX-80-0Vo.title" = "បង្ហាញក្ដារចុចលើអេក្រង់ជានិច្ច";
-/* Class = "NSButtonCell"; title = "Use verbose Console logging"; ObjectID = "7J6-zy-R20"; */
+/* Checkbox text to enable verbose Console logging */
"7J6-zy-R20.title" = "ប្រើកំណត់ហេតុកុងសូលលម្អិត";
-/* Class = "NSTabViewItem"; label = "Support"; ObjectID = "93O-x6-RLF"; */
+/* Support button text */
"93O-x6-RLF.label" = "គាំទ្រ";
-/* Class = "NSButtonCell"; title = "Download keyboard..."; ObjectID = "CTw-kf-WNS"; */
+/* Download Keyboard button text */
"CTw-kf-WNS.title" = "ទាញយកក្ដារចុច...";
-/* Class = "NSWindow"; title = "Keyman Configuration"; ObjectID = "F0z-JX-Cv5"; */
+/* Keyman Configuration window title */
"F0z-JX-Cv5.title" = "ការកំណត់រចនាសម្ព័ន្ធ Keyman";
-/* Class = "NSButtonCell"; title = "< Back"; ObjectID = "JOK-JV-n8w"; */
+/* button text to go back to previous page */
"JOK-JV-n8w.title" = "ថយក្រោយ";
-/* Class = "NSTabViewItem"; label = "Keyboard Layouts"; ObjectID = "MPN-9N-wWc"; */
-"MPN-9N-wWc.label" = "ប្លង់ក្ដារចុច";
+/* Keyboards button text */
+"MPN-9N-wWc.label" = "ក្ដារចុច";
-/* Class = "NSTextFieldCell"; title = "When the verbose logging option is on, Keyman will log actions that might help Keyman Support diagnose a problem. The Console program can be used to see a log of messages from Keyman. In Console, filter to show all messages from the \"Keyman\" process. This log can be exported and sent to Keyman support if needed."; ObjectID = "MrI-GM-7d6"; */
+/* text to explain verbose Console logging option */
"MrI-GM-7d6.title" = "នៅពេលបើកជម្រើសកំណត់ហេតុលម្អិត Keyman នឹងរក្សារទុកកំណត់ហេតុសកម្មភាពដែលអាចជួយក្រុមការងារ Keyman វិភាគបញ្ហា។ កម្មវិធីកុងសូលអាចប្រើបើកមើលសារកំណត់ហេតុពី Keyman។ ក្នុងកុងសូល ត្រងដើម្បីបង្ហាញសារទាំងអស់ពីដំណើរការរបស់ \"Keyman\"។ បើចាំបាច់ អ្នកអាចនាំចេញ ឬផ្ញើកំណត់ហេតុនេទៅក្រុមការងារ Keyman។";
-/* Class = "NSButtonCell"; title = "Forward >"; ObjectID = "eXr-8V-h1g"; */
+/* button text to move forward to the next page */
"eXr-8V-h1g.title" = "ទៅមុខ";
-/* Class = "NSButtonCell"; title = "Home"; ObjectID = "fXS-aC-CMH"; */
+/* button text to return to the home help page */
"fXS-aC-CMH.title" = "ដើម";
-/* Class = "NSTabViewItem"; label = "Options"; ObjectID = "frd-No-seV"; */
+/* Options button text */
"frd-No-seV.label" = "ជម្រើស";
-/* Class = "NSTableColumn"; headerCell.title = "Installed Keyboard"; ObjectID = "jex-Nd-Qzg"; */
+/* Installed Keyboard column heading */
"jex-Nd-Qzg.headerCell.title" = "បានដំឡើងក្ដារចុច";
-/* Class = "NSButton"; ibShadowedToolTip = "Turn this on if you are having problems with a specific keyboard or with Keyman in general."; ObjectID = "uWx-3J-U0D"; */
+/* Verbose logging tooltip text */
"uWx-3J-U0D.ibShadowedToolTip" = "បើកចុះ ប្រសិនបើអ្នកកំពុងមានបញ្ហាជាមួយ Keyman ឬក្ដារចុចណាមួយជាក់លាក់។";
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m
index 15e6ea5bd7..fc5d602ad8 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m
+++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m
@@ -29,8 +29,7 @@
- (void)windowDidLoad {
[super windowDidLoad];
- // TODO: rename
- [self.window setTitle:@"Keyboard/Package Info"];
+
[self.tabView setDelegate:self];
[self.detailsView setFrameLoadDelegate:(id)self];
[self.detailsView setPolicyDelegate:(id)self];
@@ -82,7 +81,11 @@
return YES;
}
+// TODO: refactor: any reason for this to be HTML? hard to read stringWithFormat applied to template with 16 arguments
- (NSString *)detailsHtml {
+
+ NSString *errorString = NSLocalizedString(@"message-keyboard-file-unreadable", nil);
+
@try {
NSString *htmlFormat =
@""
@@ -110,16 +113,16 @@
"Scan this code to load this keyboard on another device or "
"
share online "
""
- "Keyboard Layouts:
"
+ "%@
"
"%@"
"
"
- "Fonts:
"
+ "%@
"
"%@"
"
"
- "Package version:
%@
"
- "Author:
%@
"
- "Website:
%@
"
- "Copyright:
%@
"
+ "%@
%@
"
+ "%@
%@
"
+ "%@
%@
"
+ "%@
%@
"
""
""
"