Merge pull request #10911 from keymanapp/chore/merge-master-into-windows-updates

chore: merge master into windows-updates 💽
This commit is contained in:
Marc Durdin 2024-03-04 06:48:01 +07:00 • committed by GitHub
commit e001e6998c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 744 additions and 234 deletions

View file

@ -1,5 +1,5 @@
name: "Ubuntu packaging"
run-name: "Ubuntu packaging - ${{ github.event.client_payload.branch }} (branch ${{ github.event.client_payload.baseBranch }}), by @${{ github.event.client_payload.user }}"
run-name: "Ubuntu packaging - ${{ github.event.client_payload.branch }} (branch ${{ github.event.client_payload.baseBranch }}), by @${{ github.event.client_payload.user }}, testbuild: ${{ github.event.client_payload.isTestBuild }}"
on:
repository_dispatch:
types: ['deb-release-packaging:*', 'deb-pr-packaging:*']
@ -152,6 +152,35 @@ jobs:
!artifacts/keyman-srcpkg/
if: always()
autopkg_test:
name: Run autopkgtests
needs: [binary_packages]
runs-on: ubuntu-latest
steps:
# - name: Download Artifacts
# uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
# with:
# path: artifacts
# merge-multiple: true
# - name: Install dependencies
# run: |
# sudo DEBIAN_FRONTEND=noninteractive apt-get -q -y install autopkgtest qemu-system qemu-utils autodep8 genisoimage python3-distro-info
# - name: Build test image
# run: |
# cd "${GITHUB_WORKSPACE}/artifacts"
# autopkgtest-buildvm-ubuntu-cloud -v --release=jammy
# - name: Run tests
# run: |
# cd "${GITHUB_WORKSPACE}/artifacts"
# autopkgtest -B *.deb keyman_*.dsc -- qemu autopkgtest-jammy-amd64.img
- name: Ignore
run: |
echo "Ignored for now - until working solution is in place"
deb_signing:
name: Sign source and binary packages
needs: [sourcepackage, binary_packages]
@ -280,7 +309,9 @@ jobs:
- name: Verify API
run: |
cd linux
PKG_NAME=libkeymancore
# Extract line containing "Package: libkeymancore1" and then strip "Package: "
PKG_NAME=$(grep -E 'Package: libkeymancore([0-9]+|$)' debian/control)
PKG_NAME="${PKG_NAME#Package: }"
./scripts/deb-packaging.sh \
--gha \
--bin-pkg "${GITHUB_WORKSPACE}/artifacts/${PKG_NAME}_${{ needs.sourcepackage.outputs.VERSION }}-1${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}+jammy1_amd64.deb" \
@ -297,24 +328,24 @@ jobs:
set_status:
name: Set result status on PR builds
needs: [sourcepackage, binary_packages, api_verification]
needs: [sourcepackage, binary_packages, api_verification, autopkg_test]
runs-on: ubuntu-latest
if: ${{ always() && github.event.client_payload.isTestBuild == 'true' }}
steps:
- name: Set success
if: needs.sourcepackage.result == 'success' && needs.binary_packages.result == 'success' && needs.api_verification.result == 'success'
if: needs.sourcepackage.result == 'success' && needs.binary_packages.result == 'success' && needs.api_verification.result == 'success' && needs.autopkg_test.result == 'success'
run: |
echo "RESULT=success" >> $GITHUB_ENV
echo "MSG=Package build succeeded" >> $GITHUB_ENV
- name: Set cancelled
if: needs.sourcepackage.result == 'cancelled' || needs.binary_packages.result == 'cancelled' || needs.api_verification.result == 'cancelled'
if: needs.sourcepackage.result == 'cancelled' || needs.binary_packages.result == 'cancelled' || needs.api_verification.result == 'cancelled' || needs.autopkg_test.result == 'cancelled'
run: |
echo "RESULT=error" >> $GITHUB_ENV
echo "MSG=Package build cancelled" >> $GITHUB_ENV
- name: Set failure
if: needs.sourcepackage.result == 'failure' || needs.binary_packages.result == 'failure' || needs.api_verification.result == 'failure'
if: needs.sourcepackage.result == 'failure' || needs.binary_packages.result == 'failure' || needs.api_verification.result == 'failure' || needs.autopkg_test.result == 'failure'
run: |
echo "RESULT=failure" >> $GITHUB_ENV
echo "MSG=Package build failed" >> $GITHUB_ENV

View file

@ -1,10 +1,49 @@
# Keyman Version History
## 18.0.7 alpha 2024-02-29
* chore: Merge 17.0.270 beta back to master (#10886)
## 18.0.6 alpha 2024-02-27
* chore(linux): Temporarily disable autopkgtests gha (#10853)
* chore(linux): Update debian changelog (#10827)
## 18.0.5 alpha 2024-02-26
* fix(linux): Dynamically get package name (#10826)
* chore(linux): Add running autopkgtests on GHA (#10823)
* fix(linux): Fix autopkgtest gha (#10849)
## 18.0.4 alpha 2024-02-23
* chore(linux): Update debian changelog (#10786)
## 18.0.3 alpha 2024-02-21
* chore(deps): bump ip from 2.0.0 to 2.0.1 (#10792)
## 18.0.2 alpha 2024-02-20
* chore(linux): Add testbuild info to workflow title (#10771)
## 18.0.1 alpha 2024-02-15
* chore(common): move to 18.0 alpha (#10713)
* chore: move to 18.0 alpha
## 17.0.269 beta 2024-02-15
* docs(android): Document using gestures on touch, and remove references to Browser (#10686)
* docs(android/app): Add help page on using the banner (#10691)
* fix(web): corrects Android over-deletion of selected text, other context diffs involving selected text (#10662)
* fix(web): disables banner interaction when suggestions are absent (#10695)
* fix(web): longpress validation by base key, not current location (#10707)
## 17.0.268 beta 2024-02-15
* chore: move to beta
## 17.0.267 alpha 2024-02-14
* fix(linux): Use temp dir if we can't create cache dir (#10681)

View file

@ -1 +1 @@
18.0.2
18.0.8

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View file

@ -2,6 +2,8 @@
title: Basic Help
---
* [Using the Banner on the Keyboard](using-the-banner)
* [Switching Between Keyboards](switching-between-keyboards)
* [Installing Custom Keyboards/Dictionaries](installing-custom-packages)
@ -9,7 +11,5 @@ title: Basic Help
* [Using the Settings Screen](config/)
* [Using the Keyman Browser](using-keyman-browser)
* [Removing Keyboards](uninstalling-keyboards)
* [Removing Dictionaries](uninstalling-dictionaries)

View file

@ -1,18 +0,0 @@
---
title: Using the Keyman Browser - Keyman for Android Help
---
## Using the Keyman Browser
Step 1)
Click the Keyman Browser button in the Keyman app
Step 2)
Enter the URL of a website to visit into the address bar, for example <strong>google.com</strong>.
Keyman Browser will load the page and detect your language if it is present, and reformat it to show your language instead of square boxes.
Step 3)
Use the bookmark button to save the current page for browsing later.
Step 4)
Use the Globe icon to swap between languages.

View file

@ -0,0 +1,27 @@
---
title: Using the Banner on the Keyboard - Keyman for Android Help
---
## About the Keyboard Banner
Keyman keyboards now always display a banner above the keyboard for one of the following functionalities:
* Display suggestions (See "Using the Suggestion Banner" below)
* Display a Keyman-themed banner so popups and gestures for the top row of keys are visible
* Reserved for future functionality
## Using the Suggestion Banner
If a [dictionary is installed](installing-dictionaries) and enabled for the active Keyman keyboard, the banner will display suggestions that can be selected.
![](../android_images/settings-suggestions-ap.png)
* Drag the banner horizontally to see more suggestions
* Overly-long suggestions are partially hidden, but expand when a finger is held on them
* Banner displays up to 8 suggestions
## The Keyman Themed Banner
When suggestions are disabled or unavailable, the Keyman-themed banner will display instead. This is displayed so popups and gestures for the top row of keys are visible.
![](../android_images/themed-banner.png)

View file

@ -0,0 +1,13 @@
---
title: Gesture Hints and Tips
---
## Using Gestures on the Keyboard Keys
There are now several gestures available to interact with some keys on the keyboard. Keys which have gestures available will normally show them as a hint in the top right of the key:
![](../android_images/touch-hold-ap.png)
* **Long press**: Press and hold a key, and after a moment a submenu will appear. Slide the finger to the submenu to select a key. Release the finger, and the highlighted key from the submenu will be output.
* **Flick**: Press and hold a key, and then slide the finger in various directions on a key to reach alternate outputs. The key will animate to show the expected output when the finger gets released. A common flick is to slide down to reach numerals on the top row of the keyboard.
* **Multitap**: Some keys can be pressed repeatedly and rapidly to reach alternate outputs. Tapping rapidly twice on <kbd>Shift</kbd> will activate <kbd>Caps Lock</kbd> on many keyboards.

View file

@ -2,5 +2,6 @@
title: Contextual Help
---
* [The Keyman Menu (Phone Layout)](menu-phone)
* [The Keyman Menu (Tablet Layout)](menu-tablet)
* [The Keyboard Keys and Keyman Menu (Phone Layout)](menu-phone)
* [The Keyboard Keys and Keyman Menu (Tablet Layout)](menu-tablet)
* [Gesture Hints and Tips](gestures)

View file

@ -9,14 +9,13 @@ title: Keyman for Android (Phone Layout)
| ![](../android_images/backspace-ap.png) | Backspace |
| ![](../android_images/return-ap.png) | Return |
| ![](../android_images/shift-ap.png) | Shift key. Long press this key to access the <kbd>CTRL</kbd>, <kbd>ALT</kbd> and <kbd>CTRL</kbd><kbd>ALT</kbd> keys (which can access additional key layers) |
| ![](../android_images/touch-hold-ap.png) | Keys with a small dot in the top right corner indicate a long press key. Access further functionality by long pressing the key |
| ![](../android_images/share-a.png) | Share your text with other apps like Messages, Gmail, or Twitter. Some versions of Android also let you copy your text to the clipboard. |
| ![](../android_images/touch-hold-ap.png) | There are several [gestures](gestures) to interact with some keys on the keyboard. Keys which have gestures available will normally show a hint in the top right of the key.<br>Gestures include: long press, flick, and multitap. |
----
| | Toolbar Icons |
|---|---|
| ![](../android_images/browser-a.png) | Open the Keyman Browser to use the web in your language |
| ![](../android_images/share-a.png) | Share your text with other apps like Messages, Gmail, or Twitter. Some versions of Android also let you copy your text to the clipboard. |
| ![](../android_images/menu-icon-a.png) | Open the menu for additional options |
| ![](../android_images/font-size-a.png) | Adjust the font size |
| ![](../android_images/delete-a.png) | Delete all current text |

View file

@ -9,14 +9,13 @@ title: Keyman for Android (Tablet Layout)
| ![](../android_images/backspace-at.png) | Backspace |
| ![](../android_images/return-at.png) | Return |
| ![](../android_images/shift-at.png) | Shift key. Long press this key to access the <kbd>CTRL</kbd>, <kbd>ALT</kbd> and <kbd>CTRL</kbd><kbd>ALT</kbd> keys (which can access additional key layers) |
| ![](../android_images/touch-hold-at.png) | Keys with a small dot in the top right corner indicate a long press key. Access further functionality by long pressing the key |
| ![](../android_images/touch-hold-at.png) | There are several [gestures](gestures) to interact with some keys on the keyboard. Keys which have gestures available will normally show a hint in the top right of the key.<br>Gestures include: long press, flick, and multitap. |
----
| | Toolbar Icons |
|---|---|
| ![](../android_images/share-a.png) | Share your text with other atps like Messages, Gmail, or Twitter. Some versions of Android also let you copy your text to the clipboard. |
| ![](../android_images/browser-a.png) | Open the Keyman Browser to use the web in your language |
| ![](../android_images/menu-icon-a.png) | Open the menu for additional options |
| ![](../android_images/font-size-a.png) | Adjust the font size |
| ![](../android_images/delete-a.png) | Delete all current text |

View file

@ -12,9 +12,10 @@ title: Keyman for Android 18.0 Help
* [How To - Download and Install a Keyman Keyboard](start/installing-keyboards)
* [Enabling Keyman as a System-Wide Keyboard](start/enabling-system-keyboard)
## [Using the Menu](context/)
* [Using the menu buttons (phone layout)](context/menu-phone)
* [Using the menu buttons (tablet layout)](context/menu-tablet)
## [Using the Keyboard Keys and Menu](context/)
* [Using the keyboard keys and menu buttons (phone layout)](context/menu-phone)
* [Using the keyboard keys and menu buttons (tablet layout)](context/menu-tablet)
* [Gesture Hints and Tips](context/gestures)
## Ask for Help
* [Ask other users in the SIL Keyman Community](https://community.software.sil.org/c/keyman)
@ -26,11 +27,11 @@ title: Keyman for Android 18.0 Help
* [How To - Integrating Keyman for Android](troubleshooting/integrating)
### [Using Keyman for Android](basic/)
* [Using the Banner on the Keyboard](basic/using-the-banner)
* [Switching Between Keyboards](basic/switching-between-keyboards)
* [Installing Custom Keyboards/Dictionaries](basic/installing-custom-packages)
* [Adding Dictionaries](basic/installing-dictionaries)
* [Using the Settings Screen](basic/config/)
* [Using the Keyman Browser](basic/using-keyman-browser)
* [Removing Keyboards](basic/uninstalling-keyboards)
* [Removing Dictionaries](basic/uninstalling-dictionaries)

View file

@ -5,7 +5,7 @@ title: How To - Enabling Keyman as a System-Wide Keyboard
## Enabling System Wide Keyboards
Step 1)
Open the Keyman app and select the menu for additional options.
The screenshots below are of a device running Android 9.0 Pie.
The screenshots below are of a device running Android 12 Snow Cone.
![](../android_images/settings1-ap.png)

View file

@ -39,6 +39,7 @@ export { default as KeyMapping } from "./text/keyMapping.js";
export { default as OutputTarget } from "./text/outputTarget.js";
export * from "./text/outputTarget.js";
export { default as RuleBehavior } from "./text/ruleBehavior.js";
export * from "./text/stringDivergence.js";
export * from "./text/systemStores.js";
export * from "@keymanapp/web-utils";

View file

@ -1,6 +1,7 @@
///<reference types="@keymanapp/models-types" />
import { extendString } from "@keymanapp/web-utils";
import { findCommonSubstringEndIndex } from "./stringDivergence.js";
extendString();
@ -120,85 +121,24 @@ export default abstract class OutputTarget {
* @param from An output target (preferably a Mock) representing the prior state of the input/output system.
*/
buildTransformFrom(original: OutputTarget): Transform {
let to = this.getText();
let from = original.getText();
const toLeft = this.getTextBeforeCaret();
const fromLeft = original.getTextBeforeCaret();
let fromCaret = original.getDeadkeyCaret();
let toCaret = this.getDeadkeyCaret();
const leftDivergenceIndex = findCommonSubstringEndIndex(fromLeft, toLeft, false);
const deletedLeft = fromLeft.substring(leftDivergenceIndex)._kmwLength();
// No need for our specialized variant here.
const insertedText = toLeft.substring(leftDivergenceIndex);
// Step 1: Determine the number of left-deletions.
let maxSMPLeftMatch = fromCaret < toCaret ? fromCaret : toCaret;
const toRight = this.getTextAfterCaret();
const fromRight = original.getTextAfterCaret();
const rightDivergenceIndex = findCommonSubstringEndIndex(fromRight, toRight, true);
// We need the corresponding non-SMP caret location in order to binary-search efficiently.
// (Examining code units is much more computationally efficient.)
let maxLeftMatch = to._kmwCodePointToCodeUnit(maxSMPLeftMatch);
// Right insertions aren't supported, but right deletions will matter in some scenarios.
// In particular, once we allow right-deletion for pred-text suggestions applied with the
// caret mid-word..
const deletedRight = fromRight.substring(0, rightDivergenceIndex + 1)._kmwLength();
// 1.1: use a non-SMP-aware binary search to determine the divergence point.
let start = 0;
let end = maxLeftMatch; // the index AFTER the last possible matching char.
// This search is O(maxLeftMatch). 1/2 + 1/4 + 1/8 + ... converges to = 1.
while(start < end) {
let mid = Math.floor((end+start+1) / 2); // round up (compare more)
let fromLeft = from.substr(start, mid-start);
let toLeft = to.substr(start, mid-start);
if(fromLeft == toLeft) {
start = mid;
} else {
end = mid - 1;
}
}
// At the loop's end: `end` now holds the non-SMP-aware divergence point.
// The 'caret' is after the last matching code unit.
// 1.2: detect a possible surrogate-pair split scenario, correcting for it
// (by moving the split before the high-surrogate) if detected.
// If the split location is precisely on either end of the context, we can't
// have split a surrogate pair.
if(end > 0 && end < maxLeftMatch) {
let potentialHigh = from.charCodeAt(end-1);
let potentialFromLow = from.charCodeAt(end);
let potentialToLow = to.charCodeAt(end);
// if potentialHigh is a possible high surrogate...
if(potentialHigh >= 0xD800 && potentialHigh <= 0xDBFF) {
// and at least one potential 'low' is a possible low surrogate...
let flag = potentialFromLow >= 0xDC00 && potentialFromLow <= 0xDFFF;
flag = flag || (potentialToLow >= 0XDC00 && potentialToLow <= 0xDFFF);
// Correct the split location, moving it 'before' the high surrogate.
if(flag) {
end = end - 1;
}
}
}
// 1.3: take substring from start to the split point; determine SMP-aware length.
// This yields the SMP-aware divergence index, which gives the number of left-deletes.
let newCaret = from._kmwCodeUnitToCodePoint(end);
let deletedLeft = fromCaret - newCaret;
// Step 2: Determine the other properties.
// Since the 'after' OutputTarget's caret indicates the end of any inserted text, we
// can easily calculate the rest.
let insertedLength = toCaret - newCaret;
let delta = to._kmwSubstr(newCaret, insertedLength);
let undeletedRight = to._kmwLength() - toCaret;
let originalRight = from._kmwLength() - fromCaret;
let deletedRight = originalRight - undeletedRight;
// May occur when reverting a suggestion that had been applied mid-word.
if(deletedRight < 0) {
// Restores deleteRight characters.
delta = delta + to._kmwSubstr(toCaret, -deletedRight);
deletedRight = 0;
}
return new TextTransform(delta, deletedLeft, deletedRight);
return new TextTransform(insertedText, deletedLeft, deletedRight);
}
buildTranscriptionFrom(original: OutputTarget, keyEvent: KeyEvent, readonly: boolean, alternates?: Alternate[]): Transcription {
@ -214,6 +154,13 @@ export default abstract class OutputTarget {
* @param original An `OutputTarget` (usually a `Mock`).
*/
restoreTo(original: OutputTarget) {
this.clearSelection();
// We currently do not restore selected text; the mechanism isn't supported at present for
// all output target types - especially in regard to re-selecting the text if restored.
//
// I believe this would mostly matter if/when reverting predictions based upon selected text.
// That pattern isn't well-supported yet, though.
//
this.setTextBeforeCaret(original.getTextBeforeCaret());
this.setTextAfterCaret(original.getTextAfterCaret());
@ -223,6 +170,10 @@ export default abstract class OutputTarget {
}
apply(transform: Transform) {
// Selected text should disappear on any text edit; application of a transform
// certainly qualifies.
this.clearSelection();
if(transform.deleteRight) {
this.setTextAfterCaret(this.getTextAfterCaret()._kmwSubstr(transform.deleteRight));
}

View file

@ -0,0 +1,93 @@
// Future TODO: import from @keymanapp/common-types... once we no longer need to support ES5.
import { Uni_IsSurrogate1, Uni_IsSurrogate2 } from '@keymanapp/web-utils';
/**
* Returns the index for the code point divergence point between two strings, as measured in code
* unit coordinates.
* @param str1
* @param str2
* @param commonSuffix If false, asserts a common prefix to the strings. If true, asserts a common suffix.
* @returns The code unit index within `str1` for the start of the code point not common to both.
*
* Follows the convention of (start, end) substring parameterizations having 'end' be exclusive.
*/
export function findCommonSubstringEndIndex(str1: string, str2: string, commonSuffix: boolean): number {
/**
* The maximum number of iterations to consider; exceeding this would go past a string boundary.
*/
const maxInterval = Math.min(str1.length, str2.length);
/**
* The first valid index within the string.
*/
let start: number;
/**
* The current index within the string under consideration as the divergence point.
*/
let index: number;
/**
* The index at which to terminate the search for a divergence point.
*/
let end: number;
/**
* Index shift per loop iteration.
*/
let inc: number;
/**
* Difference in index for comparison between strings.
* Mostly matters when assuming a common right-hand side.
*/
let offset: number;
if(commonSuffix) {
start = index = str1.length - 1; // e.g. str.length == 10 => start = 9.
end = index - maxInterval; // e.g. maxInterval 8, start 9 => iterate from 9 to 2, end at 1.
inc = -1;
offset = str2.length - str1.length;
} else {
start = index = 0;
end = maxInterval; // last valid index: - 1. e.g. maxInterval 8 => iterate from 0 to 7, end at 8.
inc = 1;
offset = 0;
}
// Step 1: Find the index for the first code unit different between the strings.
for(; index != end; index += inc) {
if(str1.charAt(index) != str2.charAt(index + offset)) {
break;
}
}
// Step 2: Ensure that we're not splitting a surrogate pair.
// `index` corresponds to the first char that is different _in the direction indicated by inc_.
// If it's the start position, it can't split a (completed) surrogate pair.
if(index != start && index != end) {
// if commonLeft, high surrogate; if commonRight, low surrogate.
const commonPotentialSurrogate = str1.charCodeAt(index - inc);
// Opposite surrogate type from the previous variable.
const divergentChar1 = str1.charCodeAt(index);
const divergentChar2 = str2.charCodeAt(index + offset);
const commonSurrogateChecker = commonSuffix ? Uni_IsSurrogate2 : Uni_IsSurrogate1;
const divergentSurrogateChecker = commonSuffix ? Uni_IsSurrogate1 : Uni_IsSurrogate2;
// If the last common character if of the direction-appropriate surrogate type (for
// comprising a potential split surrogate pair representing a non-BMP char)...
if(commonSurrogateChecker(commonPotentialSurrogate)) {
// And one of the two divergent chars is a qualifying match - a surrogate
// of the opposite type...
if(divergentSurrogateChecker(divergentChar1) || divergentSurrogateChecker(divergentChar2)) {
// Our current index would split a surrogate pair; decrement the index to
// preserve the pair.
return index - inc;
}
}
}
return index;
}

View file

@ -1,22 +1,161 @@
import { assert } from 'chai';
import { Mock } from '@keymanapp/keyboard-processor';
import { Mock, findCommonSubstringEndIndex } from '@keymanapp/keyboard-processor';
import { extendString } from '@keymanapp/web-utils';
extendString(); // Ensure KMW's string-extension functionality is available.
String.kmwEnableSupplementaryPlane(false);
// A unicode-coding like alias for use in constructing non-BMP strings.
const u = String.fromCodePoint;
/**
* Returns the "Mathematical Sans-Serif Small" non-BMP encoding for
* a passed-in lowercase char between 'a' and 'z', inclusive.
* @param {*} char
* @returns
*/
const ss = (char) => {
const charCodeOffset = char.charCodeAt(0) - 'a'.charCodeAt(0);
return u(0x1d5ba + charCodeOffset);
}
describe("String divergence calculations", function() {
describe("Common prefix", () => {
it("BMP text", () => {
const result1 = findCommonSubstringEndIndex("apple", "applause", false);
assert.equal(result1, 4);
const result2 = findCommonSubstringEndIndex("applesauce", "applause", false);
assert.equal(result2, 4);
});
it("BMP edge cases", () => {
const result1 = findCommonSubstringEndIndex("applesauce", "applesauce", false);
assert.equal(result1, 10);
const result2 = findCommonSubstringEndIndex("applesauce", "banana bread", false);
assert.equal(result2, 0);
});
it("non-BMP text", () => {
const smp_ify = (str) => str.split('').map(ss).join('');
const result1 = findCommonSubstringEndIndex(
smp_ify('apple'),
smp_ify('applause'),
false
);
// 2 per non-BMP char; is in code-unit... units.
// Will avoid splitting code points, though.
assert.equal(result1, 8);
const result2 = findCommonSubstringEndIndex(
smp_ify('applesauce'),
smp_ify('applause'),
false
);
assert.equal(result2, 8);
});
it("non-BMP edge cases", () => {
const smp_ify = (str) => str.split('').map(ss).join('');
const result1 = findCommonSubstringEndIndex(
smp_ify('applesauce'),
smp_ify('applesauce'),
false
);
assert.equal(result1, 20);
const result2 = findCommonSubstringEndIndex(
smp_ify('applesauce'),
smp_ify('banana bread'),
false
);
assert.equal(result2, 0);
})
});
describe("Common suffix", () => {
it("BMP text", () => {
// att|endance
// transc|endance
const result1 = findCommonSubstringEndIndex("attendance", "transcendance", true);
assert.equal(result1, 2);
// transcend|ance
// happenst|ance
const result2 = findCommonSubstringEndIndex("transcendance", "happenstance", true);
assert.equal(result2, 8);
});
it("BMP edge cases", () => {
// If the two are equal...
const result1 = findCommonSubstringEndIndex("post-caret text", "post-caret text", true);
assert.equal(result1, -1);
// If the two are completely different...
const result2 = findCommonSubstringEndIndex("post-caret text", "supercalifragilistic", true);
assert.equal(result2, "post-caret text".length-1);
})
it("non-BMP text", () => {
const smp_ify = (str) => str.split('').map(ss).join('');
// att|endance
// trans|endance
const result1 = findCommonSubstringEndIndex(
smp_ify("attendance"),
smp_ify("transcendance"),
true
);
// 2 per non-BMP char; is in code-unit... units.
// Will avoid splitting code points; is odd b/c we get the index of the LAST char of the pair.
assert.equal(result1, 5);
// transcend|ance
// happenst|ance
const result2 = findCommonSubstringEndIndex(
smp_ify("transcendance"),
smp_ify("happenstance"),
true
);
assert.equal(result2, 17);
});
it("non-BMP edge cases", () => {
const smp_ify = (str) => str.split('').map(ss).join('');
// If the two are equal...
const result3 = findCommonSubstringEndIndex(
smp_ify("post-caret text"),
smp_ify("post-caret text"),
true
);
assert.equal(result3, -1);
// If the two are completely different...
const result2 = findCommonSubstringEndIndex(
smp_ify("post-caret text"),
smp_ify("supercalifragilistic"),
true
);
assert.equal(result2, smp_ify("post-caret text").length-1);
})
})
});
describe("Transcriptions and Transforms", function() {
var toSupplementaryPairString = function(code){
var H = Math.floor((code - 0x10000) / 0x400) + 0xD800;
var L = (code - 0x10000) % 0x400 + 0xDC00;
return String.fromCharCode(H, L);
}
// Built in-line via function. Looks functionally equivalent to "apple", but with SMP characters.
let u = toSupplementaryPairString;
// Built in-line via function. Looks functionally equivalent to "apple", but with non-BMP characters.
let smpApple = u(0x1d5ba)+u(0x1d5c9)+u(0x1d5c9)+u(0x1d5c5)+u(0x1d5be);
it("does not store an alias for related OutputTargets", function() {
@ -124,7 +263,7 @@ but not himself.`; // Sheev Palpatine, in the Star Wars prequels.
assert.equal(transcription.transform.deleteRight, 1, "Incorrect count for right-of-caret deletions");
});
it("handles deletions around the caret without text insertion (SMP text)", function() {
it("handles deletions around the caret without text insertion (non-BMP text)", function() {
try {
String.kmwEnableSupplementaryPlane(true);
var target = new Mock(smpApple, 2);
@ -216,7 +355,7 @@ but not himself.`; // Sheev Palpatine, in the Star Wars prequels.
assert.equal(transcription.transform.deleteRight, 3, "Incorrect count for right-of-caret deletions");
});
it("handles deletions around the caret with text insertion (SMP text)", function() {
it("handles deletions around the caret with text insertion (non-BMP text)", function() {
try {
String.kmwEnableSupplementaryPlane(true);
@ -297,6 +436,35 @@ but not himself.`; // Sheev Palpatine, in the Star Wars prequels.
String.kmwEnableSupplementaryPlane(false);
}
});
it('from targets with existing selection', () => {
// | |
const target = new Mock("testing testing one two three");
target.setSelection(8, 20)
const original = Mock.from(target);
target.clearSelection();
const transform = target.buildTransformFrom(original);
assert.deepEqual(transform, {
insert: '',
deleteLeft: 0,
deleteRight: 0
});
});
it('to targets with existing selection', () => {
// | |
const target = new Mock("testing testing one two three");
target.setSelection(8, 20)
const transform = {
insert: '',
deleteLeft: 0,
deleteRight: 0
};
target.apply(transform);
assert.equal(target.getText(), 'testing two three');
});
});
/*describe("Operations with deadkeys", function() {

View file

@ -400,7 +400,7 @@ export class VariableParser {
/**
* Pattern for matching a capture set reference `($[set])`
*/
public static readonly CAPTURE_SET_REFERENCE = /\(\$\[([0-9A-Za-z_]{1,32})\]\)/g;
public static readonly CAPTURE_SET_REFERENCE = /\(\$\[([0-9A-Za-z_]{1,32})\]\)/;
/**
* `$[1:variable]`

View file

@ -21,6 +21,8 @@ export { default as extendString } from "./kmwstring.js";
export { default as ManagedPromise } from "./managedPromise.js";
export { default as TimeoutPromise, timedPromise } from "./timeoutPromise.js";
export { Uni_IsSurrogate1, Uni_IsSurrogate2 } from "./surrogates.js";
// // Uncomment the following line and run the bundled output to verify successful
// // esbuild bundling of this submodule:
// console.log(Version.CURRENT.toString());

View file

@ -0,0 +1,27 @@
/*
* The definitions below are duplicated from common/web/types/util/util.ts;
* we can't downcompile the originals to ES5 when bundling with esbuild.
* `import type` stuff is fine, but not non-type `import` statements.
*
* TODO: Use those instead, once we're no longer building ES5 versions of Web.
*/
export const Uni_LEAD_SURROGATE_START = 0xD800;
export const Uni_LEAD_SURROGATE_END = 0xDBFF;
export const Uni_TRAIL_SURROGATE_START = 0xDC00;
export const Uni_TRAIL_SURROGATE_END = 0xDFFF;
/**
* @brief True if a lead surrogate
* \def Uni_IsSurrogate1
*/
export function Uni_IsSurrogate1(ch : number) {
return ((ch) >= Uni_LEAD_SURROGATE_START && (ch) <= Uni_LEAD_SURROGATE_END);
}
/**
* @brief True if a trail surrogate
* \def Uni_IsSurrogate2
*/
export function Uni_IsSurrogate2(ch : number) {
return ((ch) >= Uni_TRAIL_SURROGATE_START && (ch) <= Uni_TRAIL_SURROGATE_END);
}

View file

@ -588,7 +588,7 @@ transform_entry::apply(const std::u32string &input, std::u32string &output) cons
char32_t *s = new char32_t[group1Len + 1];
assert(s != nullptr); // TODO-LDML: OOM
// convert
substr.toUTF32((UChar32 *)s, group1Len + 1, status);
group1.toUTF32((UChar32 *)s, group1Len + 1, status);
if (!UASSERT_SUCCESS(status)) {
return 0; // TODO-LDML: memory issue
}
@ -749,12 +749,9 @@ transforms::apply(const std::u32string &input, std::u32string &output) {
for (auto group = transform_groups.begin(); group < transform_groups.end(); group++) {
// for each transform group
// break out once there's a match
// TODO-LDML: reorders
// Assume it's a non reorder group
/** Length of match within this group*/
// find the first match in this group (if present)
// TODO-LDML: check if reorder
if (group->type == any_group_type::transform) {
std::u32string subOutput;
size_t subMatched = group->transform.apply(updatedInput, subOutput);

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboardTest3 SYSTEM "../../../../../resources/standards-data/ldml-keyboards/techpreview/dtd/ldmlKeyboardTest3.dtd">
<keyboardTest3 conformsTo="techpreview">
<info keyboard="ldml_test.xml" author="srl295" name="test" />
<tests name="separate">
<test name="key-1">
<keystroke key="1" />
<check result="1:basic:OK" />
</test>
<test name="key-2">
<keystroke key="2" />
<check result="2:simple_transform:OK" />
</test>
<test name="key-3">
<keystroke key="3" />
<check result="3:simple_marker:OK" />
</test>
<test name="key-4">
<keystroke key="4" />
<check result="4:simple_reorder:OK" />
</test>
<test name="key-5">
<keystroke key="5" />
<check result="5:simple_vars:OK" />
</test>
<test name="key-6">
<keystroke key="6" />
<check result="6:map_varOK" /> <!-- TODO: 10734 There's a bug in the matching still. Come back and fix this, but the crasher is fixed -->
<!-- <check result="6:map_var:OK" /> -->
</test>
</tests>
</keyboardTest3>

View file

@ -0,0 +1,114 @@
<?xml version="1.0"?>
<keyboard3 locale="en" conformsTo="techpreview">
<info author="Steven R. Loomis" name="LDML Test"/>
<version number="1.0.0"/>
<keys>
<!-- keep the base items -->
<import base="cldr" path="techpreview/keys-Zyyy-punctuation.xml"/>
<import base="cldr" path="techpreview/keys-Zyyy-currency.xml"/>
<!-- redefine the number keys -->
<key id="1" output="1:basic:OK" />
<key id="2" output="2:simple_transform:FAIL" />
<key id="3" output="3:simple_marker:FAIL\m{marker}" />
<key id="4" output="4:simple_reorder:UNTIED" />
<key id="5" output="5:simple_vars:${varsok}"/>
<key id="6" output="6:map_var:B\m{map1}X\m{map2}"/>
</keys>
<layers formId="us">
<layer modifiers="none">
<row keys="grave 1 2 3 4 5 6 7 8 9 0 hyphen equal"/>
<row keys="q w e r t y u i o p open-square close-square backslash"/>
<row keys="a s d f g h j k l semi-colon apos"/>
<row keys="z x c v b n m comma period slash"/>
<row keys="space"/>
</layer>
<layer modifiers="shift">
<row keys="tilde bang at hash dollar percent caret amp asterisk open-paren close-paren underscore plus"/>
<row keys="Q W E R T Y U I O P open-curly close-curly pipe"/>
<row keys="A S D F G H J K L colon double-quote"/>
<row keys="Z X C V B N M open-angle close-angle question"/>
<row keys="space"/>
</layer>
<layer modifiers="caps">
<row keys="grave 1 2 3 4 5 6 7 8 9 0 hyphen equal"/>
<row keys="Q W E R T Y U I O P open-square close-square backslash"/>
<row keys="A S D F G H J K L semi-colon apos"/>
<row keys="Z X C V B N M comma period slash"/>
<row keys="space"/>
</layer>
<layer modifiers="shift caps">
<row keys="tilde bang at hash dollar percent caret amp asterisk open-paren close-paren underscore plus"/>
<row keys="q w e r t y u i o p open-curly close-curly pipe"/>
<row keys="a s d f g h j k l colon double-quote"/>
<row keys="z x c v b n m open-angle close-angle question"/>
<row keys="space"/>
</layer>
</layers>
<variables>
<string id="varsok" value="OK"/>
<!-- 6: first 13 chars and second 13 chars of alphabet -->
<set id="alpha1" value="A B C D E F G H I J K L M"/>
<set id="alpha2" value="N O P Q R S T U V W X Y Z"/>
<!-- 6: regular and rot13 alphabet -->
<set id="alpha" value="$[alpha1] $[alpha2]"/>
<set id="nycun" value="$[alpha2] $[alpha1]"/> <!-- 'nycun' in rot13 -->
</variables>
<transforms type="simple">
<transformGroup>
<!--
from to char
- - -
1 1 U
2 2 N
3 4 T
4 3 I
5 5 E
6 6 D
-->
<reorder from="U" order="0" />
<reorder from="N" order="1" />
<reorder from="I" order="2" /> <!-- the 'T' and 'I' will swap places-->
<reorder from="T" order="3" />
<reorder from="E" order="4" />
<reorder from="D" order="5" />
</transformGroup>
<!-- 6: rot-13 the last char -->
<transformGroup>
<transform from="($[alpha])\m{map2}" to="$[1:nycun]"/>
</transformGroup>
<!-- 6: restore the trailing map2 -->
<transformGroup>
<transform from="\m{map1}($[alpha])" to="\m{map1}$1\m{map2}"/>
</transformGroup>
<!-- 6: swap chars -->
<transformGroup>
<transform from="($[alpha])\m{map1}($[alpha])\m{map2}" to="$2\m{map2}$1\m{map1}" />
</transformGroup>
<!-- 6: rot-13 the last char -->
<transformGroup>
<transform from="($[alpha])\m{map1}" to="$[1:nycun]"/>
</transformGroup>
<!-- 6: restore the trailing map1 -->
<transformGroup>
<transform from="\m{map2}($[alpha])" to="\m{map2}$1\m{map1}"/>
</transformGroup>
<!-- 6: swap back -->
<transformGroup>
<transform from="($[alpha])\m{map2}($[alpha])\m{map1}" to="$2\m{map1}$1\m{map2}" />
</transformGroup>
<transformGroup>
<transform from="simple_transform:FAIL" to="simple_transform:OK" />
<!-- 3: interpret marker results -->
<transform from="FAIL\m{marker}" to="OK" />
<!-- 4: interpret reorder results -->
<transform from="UNITED" to="OK" />
<transform from="UNTIED" to="FAIL" />
<!-- 6: if untransformed, BX is a failure. -->
<transform from=":B\m{.}X\m{.}" to=":FAIL"/>
</transformGroup>
</transforms>
</keyboard3>

View file

@ -33,6 +33,7 @@ tests_without_testdata = [
# These tests have a k_001_tiny-test.xml file as well.
tests_with_testdata = [
'ldml_test',
'k_001_tiny',
'k_006_backspace',
'k_007_transform_rgx',

View file

@ -126,7 +126,6 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
let cookedFrom = transform.from;
cookedFrom = sections.vars.substituteStrings(cookedFrom, sections);
// TODO: handle 'map' case
const mapFrom = VariableParser.CAPTURE_SET_REFERENCE.exec(cookedFrom);
const mapTo = VariableParser.MAPPED_SET_REFERENCE.exec(transform.to || '');
if (mapFrom && mapTo) { // TODO-LDML: error cases

View file

@ -1,3 +1,18 @@
keyman (17.0.274-1) unstable; urgency=medium
* Fix autopkg tests
* New upstream release.
* Re-release to Debian
-- Eberhard Beilharz <eb1@sil.org> Fri, 23 Feb 2024 15:45:13 +0100
keyman (17.0.272-1) unstable; urgency=medium
* New upstream release.
* Re-release to Debian
-- Eberhard Beilharz <eb1@sil.org> Wed, 21 Feb 2024 16:36:14 +0100
keyman (16.0.145-1) unstable; urgency=medium
[Jeremy Bicha]

6
package-lock.json generated
View file

@ -8053,9 +8053,9 @@
}
},
"node_modules/ip": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
"integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==",
"optional": true
},
"node_modules/ipaddr.js": {

View file

@ -30,6 +30,8 @@ gitbranch=`git branch --show-current`
FORCE=0
HISTORY_FORCE=
fromversion=
toversion=
if [[ $# -gt 0 ]]; then
if [[ "$1" == "-f" ]]; then
@ -42,13 +44,14 @@ fi
if [[ $# -gt 0 ]]; then
# We want the action to specify the branch as a consistency check
# for now at least.
action=$1
if [[ $# -gt 1 ]]; then
base=$2
shift
else
action=help
fi
shift
if [[ $action == commit ]]; then
if [ "$base" != "master" ] && [ "$base" != "beta" ] && [[ ! "$base" =~ ^stable-[0-9]+\.[0-9]+$ ]]; then
@ -60,6 +63,13 @@ if [[ $# -gt 0 ]]; then
echo "Branch doesn't match currently checked out branch."
exit 2
fi
# commit action parameters
if [[ $# -gt 0 ]]; then
# next two parameters are --from and --to
fromversion="$1"
toversion="$2"
fi
fi
else
action="increment"
@ -93,7 +103,11 @@ npm ci
echo "increment-version.sh: running resources/build/version"
pushd "$KEYMAN_ROOT"
ABORT=0
node resources/build/version/build/src/index.js history version -t "$GITHUB_TOKEN" -b "$base" $HISTORY_FORCE || ABORT=$?
if [[ -z "$fromversion" ]]; then
node resources/build/version/build/src/index.js history version -t "$GITHUB_TOKEN" -b "$base" $HISTORY_FORCE || ABORT=$?
else
node resources/build/version/build/src/index.js history version -t "$GITHUB_TOKEN" -b "$base" $HISTORY_FORCE --from "$fromversion" --to "$toversion" || ABORT=$?
fi
if [[ $ABORT = 50 ]]; then
if [[ $FORCE = 0 ]]; then

View file

@ -184,7 +184,7 @@ export const sendCommentToPullRequestAndRelatedIssues = async (
*/
export const fixupHistory = async (
octokit: GitHub, base: string, force: boolean, writeGithubComment: boolean
octokit: GitHub, base: string, force: boolean, writeGithubComment: boolean, from?: string, to?: string
): Promise<number> => {
//
@ -194,7 +194,7 @@ export const fixupHistory = async (
let pulls: PRInformation[] = [];
try {
pulls = await reportHistory(octokit, base, force, false);
pulls = await reportHistory(octokit, base, force, false, from, to);
} catch(e) {
logWarning(String(e));
return -1;

View file

@ -108,7 +108,7 @@ const main = async (): Promise<void> => {
if(argv._.includes('history')) {
logInfo(`# Validating history for ${version}`);
changeCount = await fixupHistory(octokit, argv.base, argv.force, argv['write-github-comment']);
changeCount = await fixupHistory(octokit, argv.base, argv.force, argv['write-github-comment'], argv.from, argv.to);
logInfo(`# ${changeCount} change(s) found for ${version}\n`);
}

View file

@ -205,9 +205,6 @@ export default class KeymanEngine extends KeymanEngineBase<BrowserConfiguration,
// Automatically performs related handler setup & maintains references
// needed for related cleanup / shutdown.
this.pageIntegration = new PageIntegrationHandlers(window, this);
// Initialize supplementary plane string extensions
String.kmwEnableSupplementaryPlane(true);
this.config.finalizeInit();
if(this.ui) {

View file

@ -201,6 +201,9 @@ export default class KeymanEngine<
config.initialize(optionSpec);
// Initialize supplementary plane string extensions
String.kmwEnableSupplementaryPlane(true);
// Since we're not sandboxing keyboard loads yet, we just use `window` as the jsGlobal object.
// All components initialized below require a properly-configured `config.paths` or similar.
const keyboardLoader = new KeyboardLoader(this.interface, config.applyCacheBusting);

View file

@ -498,7 +498,9 @@ export class SuggestionBanner extends Banner {
const optionBounding = option.div.getBoundingClientRect();
if(optionBounding.left <= sample.clientX && sample.clientX < optionBounding.right) {
return option;
// If there is no backing suggestion, then there's no real selection.
// May happen when no suggestions are available.
return option.suggestion ? option : null;
} else {
const dist = (sample.clientX < optionBounding.left ? -1 : 1) * (sample.clientX - optionBounding.left);
@ -509,7 +511,8 @@ export class SuggestionBanner extends Banner {
}
}
return bestMatch;
// If there is no backing suggestion, then there's no real selection.
return bestMatch.suggestion ? bestMatch : null;
}
};
@ -557,7 +560,7 @@ export class SuggestionBanner extends Banner {
sourceTracker.source = source;
sourceTracker.scrollingHandler = (sample) => {
const newScrollLeft = this.scrollState.updateTo(sample);
this.highlightAnimation.setBaseScroll(newScrollLeft);
this.highlightAnimation?.setBaseScroll(newScrollLeft);
// Only re-enable the original suggestion, even if the touchpoint finds
// itself over a different suggestion. Might happen if a scroll boundary
@ -578,9 +581,9 @@ export class SuggestionBanner extends Banner {
};
sourceTracker.suggestion = source.currentSample.item;
markSelection(sourceTracker.suggestion);
source.currentSample.item.highlight(true);
if(sourceTracker.suggestion) {
markSelection(sourceTracker.suggestion);
}
const terminationHandler = () => {
if(sourceTracker.suggestion) {

View file

@ -443,7 +443,7 @@ export function longpressContactModel(params: GestureParams, enabledFlicks: bool
duration: spec.waitLength,
expectedResult: true
},
validateItem: (key: KeyElement) => !!key?.key.spec.sk,
validateItem: (_: KeyElement, baseKey: KeyElement) => !!baseKey?.key.spec.sk,
pathModel: {
evaluate: (path) => {
const stats = path.stats;

View file

@ -51,11 +51,11 @@
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 8.0.330.0 -->
<string name="SKBalloonOSKClosed" comment="Balloon that shows when OSK is closed">O Keyman ainda está em execução. Clique neste ícone para usar o seu teclado de idioma a qualquer momento</string>
<string name="SKBalloonOSKClosed" comment="Balloon that shows when OSK is closed">O Keyman ainda está em execução. Clique neste ícone para usar o teclado do seu idioma a qualquer momento</string>
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 14.0.234 -->
<string name="SKBalloonKeymanIsRunning" comment="Balloon that shows when user tries to start Keyman but it is already running">O keyman já está em execução. Clique no ícone do Keyman na área de notificação do sistema para usar o seu teclado de idioma</string>
<string name="SKBalloonKeymanIsRunning" comment="Balloon that shows when user tries to start Keyman but it is already running">O keyman já está em execução. Clique no ícone do Keyman na área de notificação do sistema para usar o teclado do seu idioma</string>
<!-- Context: Configuration Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -99,7 +99,7 @@
<!-- Context: Configuration Dialog - Tab names -->
<!-- String Type: PlainText -->
<!-- Introduced: 9.0.493.0 -->
<string name="S_KeepInTouch" comment="Keep in touch tab name">Manter contato</string>
<string name="S_KeepInTouch" comment="Keep in touch tab name">Manter contacto</string>
<!-- Context: Configuration Dialog - Tab names -->
<!-- String Type: PlainText -->
<!-- Introduced: 9.0.492.0 -->
@ -107,7 +107,7 @@
<!-- Context: Configuration Dialog - Captions -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Caption_Filename" comment="Keyboard download window, etc. - term for filename">Nome do arquivo:</string>
<string name="S_Caption_Filename" comment="Keyboard download window, etc. - term for filename">Nome do ficheiro:</string>
<!-- Context: Configuration Dialog - Captions -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -139,11 +139,11 @@
<!-- Context: Keyboard Install Dialog - Captions -->
<!-- String Type: PlainText -->
<!-- Introduced: 14.0 -->
<string name="S_Caption_Keyboard" comment="Keyboard install dialog - term for a single keyboard layout">Layout do teclado:</string>
<string name="S_Caption_Keyboard" comment="Keyboard install dialog - term for a single keyboard layout">Layout de teclado:</string>
<!-- Context: Keyboard Install Dialog - Captions -->
<!-- String Type: PlainText -->
<!-- Introduced: 14.0 -->
<string name="S_Caption_KeyboardLanguage" comment="Keyboard install dialog - term for caption for language selector a single keyboard layout">Idioma do teclado:</string>
<string name="S_Caption_KeyboardLanguage" comment="Keyboard install dialog - term for caption for language selector a single keyboard layout">Idioma de teclado:</string>
<!-- Context: Configuration Dialog - Captions -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -207,7 +207,7 @@
<!-- Context: Configuration Dialog - Captions -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Caption_Copyright" comment="Keyboard download window, etc. - term for copyright">Direitos autorais:</string>
<string name="S_Caption_Copyright" comment="Keyboard download window, etc. - term for copyright">Direitos de autor:</string>
<!-- Context: Configuration Dialog - Footer -->
<!-- String Type: PlainText -->
<!-- Introduced: 14.0 -->
@ -219,7 +219,7 @@
<!-- Context: Configuration Dialog - Footer -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Button_DownloadKeyboard" comment="Keyboard Layouts - download keyboard button">Baixar teclado..</string>
<string name="S_Button_DownloadKeyboard" comment="Keyboard Layouts - download keyboard button">Descarregar teclado..</string>
<!-- Context: Configuration Dialog - Keyboard Layouts tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 8.0.287.0 -->
@ -227,24 +227,24 @@
<!-- Context: Configuration Dialog - Keyboard Layouts tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Keyboards_NoKeyboardsInstalled" comment="Keyboard Layouts - notice of no keyboard layouts installed">Você não tem nenhum teclado instalado. Clique no botão Baixar Teclado para instalar um layout de teclado do website da Tavultesoft.</string>
<string name="S_Keyboards_NoKeyboardsInstalled" comment="Keyboard Layouts - notice of no keyboard layouts installed">Não tem nenhum teclado instalado. Clique no botão Descarregar Teclado para instalar um layout de teclado do website da Tavultesoft.</string>
<!-- Parameters: %1$s = keyboard layout name -->
<!-- Context: Configuration Dialog - Keyboard Layouts tab -->
<!-- Introduced: 7.1.251.0 -->
<!-- String Type: PlainText -->
<string name="SKUninstallRequireAdmin" comment="Keyboard Layouts - notice of ineligibility to uninstall a keyboard">Você só pode desinstalar o teclado \'%1$s\' se você for um Administrador</string>
<string name="SKUninstallRequireAdmin" comment="Keyboard Layouts - notice of ineligibility to uninstall a keyboard">Só é possível desinstalar o teclado \'%1$s\' se for um Administrador</string>
<!-- Context: Configuration Dialog - Keyboard Layouts tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 13.0.40.0 -->
<string name="S_Keyboard_Share" comment="Keyboard Layouts - share selected keyboard button">Compartilhar teclado</string>
<string name="S_Keyboard_Share" comment="Keyboard Layouts - share selected keyboard button">Partilhar teclado</string>
<!-- Context: Configuration Dialog - Keyboard Layouts tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 13.0.40.0 -->
<string name="S_Keyboard_Share_QRCode" comment="Keyboard Layouts - caption explaining QRCode, plus prefix to link to share">Escaneie este código para carregar este teclado em outro dispositivo ou </string>
<string name="S_Keyboard_Share_QRCode" comment="Keyboard Layouts - caption explaining QRCode, plus prefix to link to share">Digitalize este código para carregar este teclado noutro dispositivo ou </string>
<!-- Context: Configuration Dialog - Keyboard Layouts tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 13.0.40.0 -->
<string name="S_Keyboard_Share_Link" comment="Keyboard Layouts - text for link to share">compartilhar online</string>
<string name="S_Keyboard_Share_Link" comment="Keyboard Layouts - text for link to share">partilhar online</string>
<!-- Context: Configuration Dialog - Keyboard Layouts tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 13.0.40.0 -->
@ -276,31 +276,31 @@
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 9.0.480.0 -->
<string name="koDeadkeyConversion" comment="Advanced options - Base keyboard deadkeys are treated as normal keys">Tratar os defeitos de hardware como chaves simples</string>
<string name="koDeadkeyConversion" comment="Advanced options - Base keyboard deadkeys are treated as normal keys">Tratar teclas mortas como teclas simples</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.244.0 -->
<string name="koShowHints" comment="General options - show/hide hint messages (resets hint messages individually disabled)">Mostrar mensagens de sugestão</string>
<string name="koShowHints" comment="General options - show/hide hint messages (resets hint messages individually disabled)">Mostrar mensagens com sugestões</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 14.0 -->
<string name="koAutomaticallyReportErrors" comment="General options - report errors to Keyman team automatically">Automaticamente reportar erros para keyman.com</string>
<string name="koAutomaticallyReportErrors" comment="General options - report errors to Keyman team automatically">Reportar erros automaticamente para keyman.com</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 14.0 -->
<string name="koAutomaticallyReportUsage" comment="General options - report anonymous usage to Keyman team automatically">Compartilhar estatísticas de uso anônimas com keyman.com</string>
<string name="koAutomaticallyReportUsage" comment="General options - report anonymous usage to Keyman team automatically">Partilhar estatísticas de uso anónimas com keyman.com</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="koStartWithWindows" comment="Startup options - Start Keyman with Windows start">Rodar ao iniciar o Windows</string>
<string name="koStartWithWindows" comment="Startup options - Start Keyman with Windows start">Correr ao iniciar o Windows</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="koShowStartup" comment="Startup options - show/hide splash screen">Mostrar tela de advertência</string>
<string name="koShowStartup" comment="Startup options - show/hide splash screen">Mostrar ecrã de aviso</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="koShowWelcome" comment="Startup options - show/hide welcome screen">Mostrar tela de bem-vindo</string>
<string name="koShowWelcome" comment="Startup options - show/hide welcome screen">Mostrar ecrã de bem-vindo</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
@ -312,11 +312,11 @@
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.236.0 -->
<string name="koReleaseShiftKeysAfterKeyPress" comment="OSK options - Releases shift/ctrl/alt on OSK after key press">Liberar Shift/Ctrl/Alt no Teclado Virtual depois de clicar numa tecla</string>
<string name="koReleaseShiftKeysAfterKeyPress" comment="OSK options - Releases shift/ctrl/alt on OSK after key press">Ativar Shift/Ctrl/Alt no Teclado Virtual depois de clicar numa tecla</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.244.0 -->
<string name="koAutoOpenOSK" comment="OSK options - auto-open OSK">Sempre mostrar Teclado Virtual enquanto teclado Keyman estiver selecionado.</string>
<string name="koAutoOpenOSK" comment="OSK options - auto-open OSK">Mostrar sempre Teclado Virtual enquanto o teclado Keyman estiver selecionado.</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.244.0 -->
@ -357,7 +357,7 @@
<!-- Context: Configuration Dialog - Hotkeys tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Hotkey_OpenConfiguration" comment="Hotkey - open Keyman Configuration">Abrir a Configuração</string>
<string name="S_Hotkey_OpenConfiguration" comment="Hotkey - open Keyman Configuration">Abrir Configuração</string>
<!-- Context: Configuration Dialog - Hotkeys tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.1.275.0 -->
@ -385,15 +385,15 @@
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 9.0.465.0 -->
<string name="S_Support_ContactInstructions_Free" comment="">Se você tiver quaisquer problemas usando o Keyman, faça uma pergunta no Fórum da Comunidade de Keyman.</string>
<string name="S_Support_ContactInstructions_Free" comment="">Se tiver algum problema com o Keyman, coloque uma questão no Fórum da Comunidade Keyman.</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 9.0.465.0 -->
<string name="S_Button_CommunitySupport" comment="">Abrir Fórum da Comunidade de Keyman</string>
<string name="S_Button_CommunitySupport" comment="">Abrir Fórum da Comunidade Keyman</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 11.0.1500.0 -->
<string name="S_Support_CreatedBySIL" comment="Support - SIL statement">Criado pelo SIL International</string>
<string name="S_Support_CreatedBySIL" comment="Support - SIL statement">Criado por SIL International</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -405,7 +405,7 @@
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 8.0.294.0 -->
<string name="S_Support_UsefulLinks" comment="Support - Useful Links heading">Links Úteis</string>
<string name="S_Support_UsefulLinks" comment="Support - Useful Links heading">Ligações Úteis</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -417,11 +417,11 @@
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Button_ProxyConfig" comment="Options button - allows manual adjustment of proxy settings">Configurações do Proxy...</string>
<string name="S_Button_ProxyConfig" comment="Options button - allows manual adjustment of proxy settings">Configurações de Proxy...</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Button_SettingsManager" comment="Options button - access to the Settings Manager">Definições do Sistema...</string>
<string name="S_Button_SettingsManager" comment="Options button - access to the Settings Manager">Definições de Sistema...</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -429,20 +429,20 @@
<!-- Context: Download Keyboard Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_DownloadKeyboard_Title" comment="Download keyboard layout from keyman.com dialog title">Baixar teclado do site da Tavultesoft</string>
<string name="S_DownloadKeyboard_Title" comment="Download keyboard layout from keyman.com dialog title">Descarregar teclado do site da Tavultesoft</string>
<!-- Context: Download Keyboard Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_DownloadKeyboard_DownloadOnlyCheckbox" comment="Download only option checkbox">Não instalar, somente baixar</string>
<string name="S_DownloadKeyboard_DownloadOnlyCheckbox" comment="Download only option checkbox">Não instalar, apenas descarregar</string>
<!-- Parameters: %1$s = Error Message, %2$d Error Code -->
<!-- Context: Download Keyboard Dialog -->
<!-- String Type: FormatString -->
<!-- Introduced: 14.0 -->
<string name="S_DownloadKeyboard_DownloadError" comment="Message shown when there is an error downloading the keyboard package">Não foi possível baixar o teclado, erro %2$d: %1$s</string>
<string name="S_DownloadKeyboard_DownloadError" comment="Message shown when there is an error downloading the keyboard package">Não foi possível descarregar o teclado, erro %2$d: %1$s</string>
<!-- Context: Download Keyboard Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 14.0 -->
<string name="S_Button_Back" comment="Back button">&lt; de volta</string>
<string name="S_Button_Back" comment="Back button">&lt; Anterior</string>
<!-- Context: Install Keyboard Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -462,7 +462,7 @@
<!-- Context: Proxy Configuration Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_ProxyConfiguration_Title" comment="Proxy configuration dialog title">Configuração do Servidor Proxy</string>
<string name="S_ProxyConfiguration_Title" comment="Proxy configuration dialog title">Configuração de Servidor Proxy</string>
<!-- Context: Proxy Configuration Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -474,11 +474,11 @@
<!-- Context: Proxy Configuration Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_ProxyConfiguration_Username" comment="Proxy dialog - fillable-field username">Usuário: </string>
<string name="S_ProxyConfiguration_Username" comment="Proxy dialog - fillable-field username">Utilizador: </string>
<!-- Context: Proxy Configuration Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_ProxyConfiguration_Password" comment="Proxy dialog - fillable-field password">Senha: </string>
<string name="S_ProxyConfiguration_Password" comment="Proxy dialog - fillable-field password">Palavra-passe: </string>
<!-- Context: Base Keyboard Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 9.0.445.0 -->
@ -486,8 +486,8 @@
<!-- Context: Base Keyboard Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 9.0.445.0 -->
<string name="S_BaseKeyboard_Text" comment="Base keyboard dialog description">Selecione o script latim base
teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente ao seu layout preferido.</string>
<string name="S_BaseKeyboard_Text" comment="Base keyboard dialog description">Selecione o teclado latino básico
que utiliza no Windows. O teclado Keyman irá se adaptar automaticamente ao seu layout preferido.</string>
<!-- Context: Hotkey Dialog -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
@ -496,7 +496,7 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Hotkey Dialog -->
<!-- Introduced: 7.0.241.0 -->
<!-- String Type: FormatString -->
<string name="SKSetHotkey_Language" comment="Hotkey dialog - message when setting hotkey for a language">Selecione uma tecla de atalho padrão ou escolha \'Personalizado\' e segure Ctrl, Shift e/ou Alt e digite a tecla de atalho desejada para o idioma %1$s:</string>
<string name="SKSetHotkey_Language" comment="Hotkey dialog - message when setting hotkey for a language">Selecione uma tecla de atalho padrão ou escolha \'Personalizado\' e mantenha pressionadas as teclas Ctrl, Shift e/ou Alt e escreva a tecla de atalho desejada para o idioma %1$s:</string>
<!-- Context: Hotkey Dialog -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
@ -505,17 +505,17 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Hotkey Dialog -->
<!-- Introduced: 7.0.230.0 -->
<!-- String Type: FormatString -->
<string name="SKUnsafeHotkey" comment="Hotkey dialog - warning of hotkey conflict with standard keyboard use">A tecla de atalho %1$s entrará em conflito com o uso normal do teclado. Você deve usar pelo menos Ctrl ou Alt. Você quer alterar isto agora\?</string>
<string name="SKUnsafeHotkey" comment="Hotkey dialog - warning of hotkey conflict with standard keyboard use">A tecla de atalho %1$s entrará em conflito com o uso normal do teclado. É necessário utilizar pelo menos Ctrl ou Alt. Quer alterar isto agora\?</string>
<!-- Parameters: %1$s = Hotkey, %2$s = Conflicting keyboard -->
<!-- Context: Hotkey Dialog -->
<!-- Introduced: 7.0.230.0 -->
<!-- String Type: FormatString -->
<string name="SKHotkeyConflicts_Keyboard" comment="Hotkey dialog - warning of hotkey conflict with hotkey for another keyboard">A tecla de atalho %1$s conflita com a tecla de atalho selecionada para o teclado %2$s. Se você continuar, a tecla de atalho para o teclado %2$s será limpa. Continuar?</string>
<string name="SKHotkeyConflicts_Keyboard" comment="Hotkey dialog - warning of hotkey conflict with hotkey for another keyboard">A tecla de atalho %1$s entra em conflito com a tecla de atalho selecionada para o teclado %2$s. Se continuar, a tecla de atalho para o teclado %2$s será apagada. Continuar?</string>
<!-- Parameters: %1$s = Hotkey -->
<!-- Context: Hotkey Dialog -->
<!-- Introduced: 14.0.117 -->
<!-- String Type: FormatString -->
<string name="SKHotkeyConflicts_Interface" comment="Hotkey dialog - warning of hotkey conflict with hotkey for another interface hotkey">A tecla de atalho %1$s está em conflito com outra chave de acesso. Se continuar, a outra tecla de atalho será apagada. Continuar?</string>
<string name="SKHotkeyConflicts_Interface" comment="Hotkey dialog - warning of hotkey conflict with hotkey for another interface hotkey">A tecla de atalho %1$s está em conflito com outra tecla de atalho. Se continuar, a outra tecla de atalho será apagada. Continuar?</string>
<!-- Context: Online Update Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -523,11 +523,11 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Online Update Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Update_NewVersionAvailable" comment="Update dialog - updates available text">Atualizações para o Keyman estão disponíveis agora</string>
<string name="S_Update_NewVersionAvailable" comment="Update dialog - updates available text">Há atualizações disponíveis para o Keyman</string>
<!-- Context: Online Update Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.1.255.0 -->
<string name="S_Update_NewVersionPrompt" comment="Update dialog - prompt to select updates">Favor selecionar as atualizações que você deseja instalar:</string>
<string name="S_Update_NewVersionPrompt" comment="Update dialog - prompt to select updates">Selecione as atualizações que deseja instalar:</string>
<!-- Context: Online Update Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -565,12 +565,12 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Online Update Dialog -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKUpdate_UnableToContact" comment="Update dialog - unable to access keyman.com warning">Não foi possível contatar o site da Tavultesoft - certifique-se de estar conectado à Internet e tente novamente.</string>
<string name="SKUpdate_UnableToContact" comment="Update dialog - unable to access keyman.com warning">Não foi possível contactar o site da Tavultesoft - certifique-se que está ligado à Internet e tente novamente.</string>
<!-- Parameters: %1$s = Error message -->
<!-- Context: Online Update Dialog -->
<!-- Introduced: 7.0.230.0 -->
<!-- String Type: FormatString -->
<string name="SKUpdate_UnableToContact_Error" comment="Update dialog - unable to access keyman.com error message">Não foi possível contatar keyman.com - por favor, certifique-se de que você tem uma conexão de Internet ativa e tente novamente. O erro recebido foi: %1$s</string>
<string name="SKUpdate_UnableToContact_Error" comment="Update dialog - unable to access keyman.com error message">Não foi possível contactar keyman.com - por favor, certifique-se de que tem uma ligação de Internet ativa e tente novamente. O erro recebido foi: %1$s</string>
<!-- Context: Online Update Dialog -->
<!-- String Type: FormatString -->
<!-- Introduced: 8.0.288.0 -->
@ -578,7 +578,7 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Online Update Dialog -->
<!-- String Type: FormatString -->
<!-- Introduced: 8.0.288.0 -->
<string name="SKUpdate_IconText" comment="Update icon - text">Clique neste ícone para baixar e instalar atualizações</string>
<string name="SKUpdate_IconText" comment="Update icon - text">Clique neste ícone para descarregar e instalar atualizações</string>
<!-- Context: Online Update Dialog -->
<!-- String Type: FormatString -->
<!-- Introduced: 8.0.288.0 -->
@ -606,7 +606,7 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Splash Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 9.0.341.0 -->
<string name="S_Splash_ShowAtStartup" comment="Show at Startup toggle">Mostrar esta tela na inicialização</string>
<string name="S_Splash_ShowAtStartup" comment="Show at Startup toggle">Mostrar este ecrã ao início</string>
<!-- Context: _LanguageInfo -->
<!-- String Type: PlainText -->
<!-- Introduced: 8.0.278.0 -->
@ -614,15 +614,15 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: _LanguageInfo -->
<!-- String Type: PlainText -->
<!-- Introduced: 8.0.278.0 -->
<string name="S_MoreUILanguagesMenu" comment="More UI languages online menu item">Encontre outros idiomas de exibição online...</string>
<string name="S_MoreUILanguagesMenu" comment="More UI languages online menu item">Encontre outros idiomas de interface online...</string>
<!-- Context: _LanguageInfo -->
<!-- String Type: PlainText -->
<!-- Introduced: 9.0.525.0 -->
<string name="S_ContributeUILanguagesMenu" comment="Link to contribute to language UI">Ajude a traduzir a interface do usuário...</string>
<string name="S_ContributeUILanguagesMenu" comment="Link to contribute to language UI">Ajude a traduzir a interface do utilizador...</string>
<!-- Context: _LanguageInfo -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKUILanguageName" comment="User interface language name in the UI language">Português do Portugal</string>
<string name="SKUILanguageName" comment="User interface language name in the UI language">Português de Portugal</string>
<!-- Context: _LanguageInfo -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
@ -630,11 +630,11 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: _LanguageInfo -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKLanguageCode" comment="The language code for the current translation">por-BR</string>
<string name="SKLanguageCode" comment="The language code for the current translation">por-PT</string>
<!-- Context: _LanguageInfo -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKDefaultLanguageCode" comment="The default language code for this product. This should be the language that the product is created in. For Keyman this must stay 'en', for all translations.">por-BR</string>
<string name="SKDefaultLanguageCode" comment="The default language code for this product. This should be the language that the product is created in. For Keyman this must stay 'en', for all translations.">por-PT</string>
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
@ -642,21 +642,21 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Hints -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.244.0 -->
<string name="S_Button_ResetHints" comment="Hint - options tab button to reset hints">Ressetar Sugestões</string>
<string name="S_Button_ResetHints" comment="Hint - options tab button to reset hints">Repor Sugestões</string>
<!-- Context: Hints -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.244.0 -->
<string name="SKHintsReset" comment="Hint - options tab dialog confirming reset of hints">Todas as mensagens de sugestão foram ressetadas e serão mostradas novamente.</string>
<string name="SKHintsReset" comment="Hint - options tab dialog confirming reset of hints">Todas as mensagens de sugestões foram repostas e serão mostradas novamente.</string>
<!-- Context: Hints -->
<!-- Introduced: 7.0.244.0 -->
<!-- String Type: HintTitle -->
<!-- DevNote: this is a constructed identifier so won't appear in a search with i18n-check-unused-strings.sh -->
<string name="HintTitle_KH_EXITPRODUCT" comment="Hint - dialog title upon attempting to exit product">Sair do chave\?</string>
<string name="HintTitle_KH_EXITPRODUCT" comment="Hint - dialog title upon attempting to exit product">Sair de Keyman\?</string>
<!-- Context: Hints -->
<!-- Introduced: 7.0.244.0 -->
<!-- String Type: Hint -->
<!-- DevNote: this is a constructed identifier so won't appear in a search with i18n-check-unused-strings.sh -->
<string name="Hint_KH_EXITPRODUCT" comment="Hint - asks for confirmation, explains the difference between de-activating a keyboard layout and closing Product">Você tem certeza que deseja sair do Keyman? Seus teclados de teclado ainda serão listados nos idiomas do Windows, mas não ficarão funcionais até reiniciar o Keyman.</string>
<string name="Hint_KH_EXITPRODUCT" comment="Hint - asks for confirmation, explains the difference between de-activating a keyboard layout and closing Product">Tem a certeza que deseja sair do Keyman? Os teclados do Keyman ainda serão listados nos idiomas do Windows, mas não funcionarão até reiniciar o Keyman.</string>
<!-- Context: Hints -->
<!-- Introduced: 7.0.244.0 -->
<!-- String Type: HintTitle -->
@ -666,11 +666,11 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Introduced: 7.0.244.0 -->
<!-- String Type: Hint -->
<!-- DevNote: this is a constructed identifier so won't appear in a search with i18n-check-unused-strings.sh -->
<string name="Hint_KH_CLOSEOSK" comment="Hint - explains that Product is still running and informs how to reopen OSK">Você fechou o Teclado Virtual. Keyman Desktop ainda está rodando. Você pode abrir o Teclado Virtual em qualquer momento por clicar no ícone do Keyman Desktop e selecionar \"Teclado Virtual\"</string>
<string name="Hint_KH_CLOSEOSK" comment="Hint - explains that Product is still running and informs how to reopen OSK">Fechou o Teclado Virtual. O Keyman Desktop ainda está a correr. Pode abrir o Teclado Virtual a qualquer momento ao clicar no ícone do Keyman Desktop e selecionar \"Teclado Virtual\"</string>
<!-- Context: Hints -->
<!-- String Type: PlainText -->
<!-- Introduced: 10.0.836.0 -->
<string name="S_HintDialog_DontShowHintAgain" comment="Hint dialog - caption of checkbox at bottom of dialog">Não exibir esta dica novamente</string>
<string name="S_HintDialog_DontShowHintAgain" comment="Hint dialog - caption of checkbox at bottom of dialog">Não mostrar esta dica novamente</string>
<!-- Context: Help Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -678,7 +678,7 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Help Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Help_Product" comment="Help - help contents link title">Conteudo da Ajuda</string>
<string name="S_Help_Product" comment="Help - help contents link title">Conteúdo de Ajuda</string>
<!-- Context: Help Dialog -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -690,15 +690,15 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Toolbar Context Help -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Toolbar_ViewOnScreenKeyboard" comment="Toolbar help - View OSK pop-up text">Ver no teclado da tela</string>
<string name="S_Toolbar_ViewOnScreenKeyboard" comment="Toolbar help - View OSK pop-up text">Ver no teclado do ecrã</string>
<!-- Context: Toolbar Context Help -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Toolbar_ViewFontHelper" comment="Toolbar help - View Font Helper pop-up text">Ver Auxiliar da Fonte</string>
<string name="S_Toolbar_ViewFontHelper" comment="Toolbar help - View Font Helper pop-up text">Ver Ajuda de Fonte</string>
<!-- Context: Toolbar Context Help -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Toolbar_ViewCharacterMap" comment="Toolbar help - View Character Map pop-up text">Visualizar Mapa de Caracteres</string>
<string name="S_Toolbar_ViewCharacterMap" comment="Toolbar help - View Character Map pop-up text">Ver Mapa de Caracteres</string>
<!-- Context: Toolbar Context Help -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -710,19 +710,19 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Toolbar Context Help -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Toolbar_CloseOnScreenKeyboard" comment="Toolbar help - Close OSK pop-up text">Fechar no teclado da tela</string>
<string name="S_Toolbar_CloseOnScreenKeyboard" comment="Toolbar help - Close OSK pop-up text">Fechar no teclado do ecrã</string>
<!-- Context: System Tray Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Menu_SwitchKeymanOff" comment="Systray item - Switch Keyman Off [&amp; precedes alt + access-character]">Alternar Keyman &amp;Desligado</string>
<string name="S_Menu_SwitchKeymanOff" comment="Systray item - Switch Keyman Off [&amp; precedes alt + access-character]">Desativar Keyman &amp;Desligado</string>
<!-- Context: System Tray Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Menu_OnScreenKeyboard" comment="Systray item - OSK [&amp; precedes alt + access-character]">Na tela &amp;teclado</string>
<string name="S_Menu_OnScreenKeyboard" comment="Systray item - OSK [&amp; precedes alt + access-character]">No ecrã &amp;teclado</string>
<!-- Context: System Tray Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Menu_FontHelper" comment="Systray item - Font Helper [&amp; precedes alt + access-character]">&amp;Font Helper</string>
<string name="S_Menu_FontHelper" comment="Systray item - Font Helper [&amp; precedes alt + access-character]">&amp;Ajuda de Fontes</string>
<!-- Context: System Tray Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -742,11 +742,11 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: System Tray Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_Menu_Exit" comment="Systray item - Exit [&amp; precedes alt + access-character]">E&amp;xit</string>
<string name="S_Menu_Exit" comment="Systray item - Exit [&amp; precedes alt + access-character]">E&amp;Sair</string>
<!-- Context: On Screen Keyboard Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_OSKContext_FadeWhenInactive" comment="OSK right-click menu - fade OSK when mouse is elsewhere">Desvanecer quando inativo</string>
<string name="S_OSKContext_FadeWhenInactive" comment="OSK right-click menu - fade OSK when mouse is elsewhere">Transparente quando inativo</string>
<!-- Context: On Screen Keyboard Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
@ -754,11 +754,11 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: On Screen Keyboard Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_OSKContext_SaveAsWebPage" comment="OSK right-click menu - save diagram of active keyboard layout as a web page">Salvar como Página da Web...</string>
<string name="S_OSKContext_SaveAsWebPage" comment="OSK right-click menu - save diagram of active keyboard layout as a web page">Guardar como Página da Web...</string>
<!-- Context: On Screen Keyboard Menu Items -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->
<string name="S_OSKContext_Print" comment="OSK right-click menu - print diagram of active keyboard layout">Print...</string>
<string name="S_OSKContext_Print" comment="OSK right-click menu - print diagram of active keyboard layout">Imprimir...</string>
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
@ -781,17 +781,17 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.0.230.0 -->
<!-- String Type: FormatString -->
<string name="SKKeyboardAlreadyInstalled" comment="Notice during keyboard layout installation that a keyboard layout with the same name is already installed.">Um teclado com o nome \'%1$s\' já está instalado. Se você continuar, será desinstalado antes que o novo seja instalado. Continuar?</string>
<string name="SKKeyboardAlreadyInstalled" comment="Notice during keyboard layout installation that a keyboard layout with the same name is already installed.">Um teclado com o nome \'%1$s\' já está instalado. Se continuar, será desinstalado antes que o novo seja instalado. Continuar?</string>
<!-- Parameters: %1$s = Keyboard name, %2$s = Package name -->
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.0.230.0 -->
<!-- String Type: FormatString -->
<string name="SKKeyboardPartOfPackage" comment="Notice of need to uninstall an entire package">O teclado \'%1$s\' é parte do pacote \'%2$s\'. Você deve desinstalar o pacote inteiro. Continuar?</string>
<string name="SKKeyboardPartOfPackage" comment="Notice of need to uninstall an entire package">O teclado \'%1$s\' é parte do pacote \'%2$s\'. Deverá desinstalar o pacote inteiro. Continuar?</string>
<!-- PArameters: %1$s = BCP 47 code -->
<!-- Context: Formatted Messages -->
<!-- Introduced: 14.0.211 -->
<!-- String Type: FormatString -->
<string name="SKInstallLanguageTransientLimit" comment="Message shown when Keyman is unable to install a Windows language for a keyboard">Não foi possível instalar o idioma do teclado; Windows tem um limite de 4 idiomas \"transientes\", e talvez você tenha atingido este limite.</string>
<string name="SKInstallLanguageTransientLimit" comment="Message shown when Keyman is unable to install a Windows language for a keyboard">Não foi possível instalar o idioma do teclado; Windows tem um limite de 4 idiomas \"transientes\", e talvez tenha atingido este limite.</string>
<!-- Parameters: %1$s = Package Name -->
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.0.230.0 -->
@ -800,7 +800,7 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKOSNotSupported" comment="Notice of unsupported operating system">Este sistema de operação não é suportado. Favor contatar Tavultesoft para mais detalhes.</string>
<string name="SKOSNotSupported" comment="Notice of unsupported operating system">Este sistema operativo não é suportado. Contacte Tavultesoft para mais detalhes.</string>
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
@ -808,7 +808,7 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKCouldNotFindHelp" comment="Notice of help file not found">O arquivo de ajuda não pôde ser encontrado.</string>
<string name="SKCouldNotFindHelp" comment="Notice of help file not found">Não foi possível encontrar o ficheiro de ajuda.</string>
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
@ -820,22 +820,22 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKDownloadProgress_Title" comment="Notice of file downloading">Baixando Arquivo</string>
<string name="SKDownloadProgress_Title" comment="Notice of file downloading">Descarregando ficheiro</string>
<!-- Parameters: %1$s = Keyboard name -->
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.0.230.0 -->
<!-- String Type: FormatString -->
<string name="SKUninstallOnScreenKeyboard" comment="Request for confirmation to uninstall OSK for a keyboard layout">Tem certeza que deseja remover o teclado na tela instalado para %1$s?</string>
<string name="SKUninstallOnScreenKeyboard" comment="Request for confirmation to uninstall OSK for a keyboard layout">Tem a certeza que deseja remover o teclado no ecrã instalado para %1$s?</string>
<!-- Parameters: %1$s = Keyboard name -->
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.0.239.0 -->
<!-- String Type: FormatString -->
<string name="SKUninstallKeyboard" comment="Request for confirmation to uninstall keyboard layout">Tem certeza que deseja desinstalar o teclado %1$s\?</string>
<string name="SKUninstallKeyboard" comment="Request for confirmation to uninstall keyboard layout">Tem a certeza que deseja desinstalar o teclado %1$s\?</string>
<!-- Parameters: %1$s = Package name, %2$s: Fonts list -->
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.0.239.0 -->
<!-- String Type: FormatString -->
<string name="SKUninstallPackage" comment="Request for confirmation to uninstall a package">Tem certeza que deseja desinstalar o pacote %1$s\?\n\n%2$s</string>
<string name="SKUninstallPackage" comment="Request for confirmation to uninstall a package">Tem a certeza que deseja desinstalar o pacote %1$s\?\n\n%2$s</string>
<!-- Parameters: %1$s = Fonts list -->
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.1.270.0 -->
@ -844,7 +844,7 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKUnicodeData_Build" comment="Request to build Unicode Character Map database">O Mapa de Caracteres possui um banco de dados de caracteres que precisa ser construído antes de poder ser usado. Construí-lo agora\?</string>
<string name="SKUnicodeData_Build" comment="Request to build Unicode Character Map database">O Mapa de Caracteres possui um banco de dados de caracteres que precisa ser construído antes de poder ser utilizado. Construí-lo agora\?</string>
<!-- Parameters: %1$s = Error detail string -->
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.0.230.0 -->
@ -864,15 +864,15 @@ teclado que você usa no Windows. Teclado Keyman irá se adaptar automaticamente
<!-- Context: Formatted Messages -->
<!-- Introduced: 7.0.241.0 -->
<!-- String Type: FormatString -->
<string name="SKCannotStartProduct" comment="Error from Keyman failing to start keyman.exe due to an access denied or file not found">O keyman não conseguiu iniciar. Por favor, verifique suas configurações de segurança para certificar-se de que o keyman.exe do programa é permitido iniciar antes de continuar. O erro retornado foi:\n\n\"%1$s\"\n\nVocê quer tentar iniciar o Keyman novamente agora\?</string>
<string name="SKCannotStartProduct" comment="Error from Keyman failing to start keyman.exe due to an access denied or file not found">O keyman não conseguiu iniciar. Por favor, verifique suas configurações de segurança para certificar-se de que o programa keyman.exe é permitido iniciar antes de continuar. O erro retornado foi:\n\n\"%1$s\"\n\nQuer tentar iniciar o Keyman novamente agora\?</string>
<!-- Context: Formatted Messages -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
<string name="SKDebuggingWarning" comment="Warning upon starting debugging in the Options tab">As informações de depuração do keyman serão armazenadas em um arquivo de log chamado %LOCALAPPDATA%\Keyman\Diag\system#.etl (onde # é um número). Você deve sair do Keyman antes de tentar excluir este arquivo.\n\n\AVISO: Este arquivo pode crescer grande rapidamente. Permitir a depuração pode tornar o sistema mais lento e só deve ser feito se recomendado pelo suporte técnico.\n\nATENÇÃO: Por favor, note que o arquivo de log de depuração registra todos os traços de tecla que você digita. Você só deve ativar o log de depuração durante uma sessão de diagnóstico ou depuração.</string>
<string name="SKDebuggingWarning" comment="Warning upon starting debugging in the Options tab">As informações de depuração do keyman serão armazenadas em um ficheiro de log chamado %LOCALAPPDATA%\Keyman\Diag\system#.etl (onde # é um número). Deverá sair do Keyman antes de tentar excluir este ficheiro.\n\n\AVISO: Este ficheiro pode crescer grande rapidamente. Permitir a depuração pode tornar o sistema mais lento e só deve ser feito se recomendado pelo suporte técnico.\n\nATENÇÃO: Por favor, note que o ficheiro de log de depuração registra todos os traços de tecla que digita. Só deve ativar o log de depuração durante uma sessão de diagnóstico ou depuração.</string>
<!-- Context: OSK Font Helper -->
<!-- String Type: FormatString -->
<!-- Introduced: 8.0.294.0 -->
<string name="S_OSK_FontHelper_PleaseWait" comment="OSK Font helper message">Por favor, aguarde enquanto busca fontes relacionadas com o teclado %1$s</string>
<string name="S_OSK_FontHelper_PleaseWait" comment="OSK Font helper message">Por favor, aguarde enquanto procura fontes relacionadas com o teclado %1$s</string>
<!-- Context: OSK Font Helper -->
<!-- String Type: FormatString -->
<!-- Introduced: 8.0.294.0 -->