Merge pull request #15457 from keymanapp/auto/A19S20-merge-master-into-user-dict

auto: A19S20 merge master into user-dict 📖
This commit is contained in:
Keyman Server 2026-01-16 11:44:41 +01:00 • committed by GitHub
commit ea1c7e67e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
179 changed files with 6586 additions and 3482 deletions

144
.github/workflows/README.md vendored Normal file
View file

@ -0,0 +1,144 @@
# api-verification.yml: checks Core API for incompatible changes
This action automatically verifies that the API of Keyman Core did not
change in incompatible ways without incrementing the API version number.
It applies to all platforms that use Core, even though we only run it on
Linux.
- The action gets triggered by the completion of the Ubuntu packaging
workflow (`deb-packaging.yml`).
- The API version is defined in `core/CORE_API_VERSION.md`.
- The baseline file for comparing the API is
`linux/debian/libkeymancore${API_VERSION}.symbols`. The action will
re-create this file and and makes it available as an artifact.
- The API checks are implemented in `linux/scripts/verify_api.inc.sh`.
More information about the API verification can be found in
`docs/core-api-verification.md`.
# auto-merge-keyman-server-pr.yml
TODO
# build-test-publish-docker.yml
TODO
# cleanup-ghcr.yml
TODO
# close-linked-issues-for-merged-prs.yml
TODO
# core-arm64-windows-test.yml: Test Keyman Core on Windows/ARM64
This action allows us to test Keyman Core for Windows on ARM64 architecture with
a GitHub agent, as we do not have any TeamCity Windows build agents with ARM64
arch.
It will normally be triggered as part of a test build from the
resources/teamcity/triggers/trigger-test-builds.sh script.
You can manually trigger a core-arm64-windows-test action on GitHub on your fork
of keymanapp/keyman. This is normally only needed to test changes to the action
itself:
- push the changes to your fork of keymanapp/keyman: `git push myfork HEAD:master`
- make sure you have GHA enabled in the settings of your fork
- seet `GITHUB_TOKEN=<your_gh_token>`
- trigger a build with:
```bash
curl --write-out '\n' --request POST \
--header "Accept: application/vnd.github+json" \
--header "Authorization: token $GITHUB_TOKEN" \
--data "{ \"event_type\": \"core-arm64-windows-test: master\", \
\"client_payload\": { \
\"buildSha\": \"$(git rev-parse refs/heads/master)\", \
\"branch\": \"master\", \
\"user\": \"${USER}\", \
\"isTestBuild\": \"true\", \
\"force\": \"true\"}" \
https://api.github.com/repos/<yourgithubname>/keyman/dispatches
```
To trigger a build for PR #1234 in a branch `my-pr-branch` this would look similar
to this:
```bash
curl --write-out '\n' --request POST \
--header "Accept: application/vnd.github+json" \
--header "Authorization: token $GITHUB_TOKEN" \
--data "{ \"event_type\": \"core-arm64-windows-test: PR #1234\", \
\"client_payload\": { \
\"buildSha\": \"$(git rev-parse refs/heads/my-pr-branch)\", \
\"branch\": \"my-pr-branch\", \
\"user\": \"${USER}\", \
\"isTestBuild\": \"true\", \
\"force\": \"true\"}" \
https://api.github.com/repos/<yourgithubname>/keyman/dispatches
```
....
# crowdin.yml: Upload translation sources to [Crowdin](translate.keyman.com)
This action automatically updates the English source strings on Crowdin
https://crowdin.com/project/keyman/sources/files
based on the root [crowdin.yml](../../crowdin.yml) configuration file. The daily cron job currently runs at 6:00AM.
This should match the behavior of locally using the [Crowdin CLI to upload sources](https://crowdin.github.io/crowdin-cli/commands/crowdin-upload-sources).
# deb-packaging.yml: Ubuntu Packaging GitHub Action
You can manually trigger a deb-packaging action on GitHub on your fork
of keymanapp/keyman. This is normally only needed to test changes to the action
itself:
- push the changes to your fork of keymanapp/keyman: `git push myfork HEAD:master`
- make sure you have GHA enabled in the settings of your fork
- seet `GITHUB_TOKEN=<your_gh_token>`
- trigger a build with:
```bash
curl --write-out '\n' --request POST \
--header "Accept: application/vnd.github+json" \
--header "Authorization: token $GITHUB_TOKEN" \
--data "{ \"event_type\": \"deb-pr-packaging: master\", \
\"client_payload\": { \
\"buildSha\": \"$(git rev-parse refs/heads/master)\", \
\"branch\": \"master\", \
\"baseBranch\": \"master\", \
\"baseRef\": \"$(git rev-parse refs/heads/master^)\", \
\"user\": \"${USER}\", \
\"isTestBuild\": \"true\", \
\"force\": \"true\"}" \
https://api.github.com/repos/<yourgithubname>/keyman/dispatches
```
To trigger a build for PR #1234 in a branch `pr-1234` this would look similar
to this:
```bash
curl --write-out '\n' --request POST \
--header "Accept: application/vnd.github+json" \
--header "Authorization: token $GITHUB_TOKEN" \
--data "{ \"event_type\": \"deb-pr-packaging: PR #1234\", \
\"client_payload\": { \
\"buildSha\": \"$(git rev-parse refs/heads/pr-1234)\", \
\"branch\": \"pr-1234\", \
\"baseBranch\": \"master\", \
\"baseRef\": \"$(git rev-parse refs/heads/master)\", \
\"user\": \"${USER}\", \
\"isTestBuild\": \"true\", \
\"force\": \"true\"}" \
https://api.github.com/repos/<yourgithubname>/keyman/dispatches
```
# labeler.yml
TODO
# npm-publish.yml
TODO
# pr-build-status.yml
TODO

View file

@ -0,0 +1,167 @@
#
# This workflow tests Keyman Core on ARM64/Windows; we cannot use our TeamCity
# agents because we have no ARM64 Windows agents.
#
# It is triggered by a repository_dispatch event with the type
# `core-arm64-windows-test:*`.
#
name: "Keyman Core - ARM64/Windows test"
run-name: "Keyman Core - ARM64/Windows test - ${{ github.event.client_payload.branch }} by @${{ github.event.client_payload.user }}"
on:
repository_dispatch:
types: ['core-arm64-windows-test:*']
# Inputs:
#
# buildSha: The SHA of the commit to build, e.g. of the branch or
# refs/pull/1234/head for PR
# isTestBuild: true for PR and test builds, false for release builds
# force: true to run this action on a fork of keymanapp/keyman
#
# Descriptive inputs:
#
# branch: Name of the branch to build, generally, `master`, `beta`,
# `stable-x.y`, or for a PR `#1234`. Used only in the action
# title
# user: The user that triggered the build or created the PR. Used
# only in the action title
env:
GH_TOKEN: ${{ github.token }}
STATUS_CONTEXT: 'Keyman Core - ARM64 test'
_builder_timings: false
jobs:
core-arm64-windows-test:
name: Keyman Core ARM64/Windows test
if: github.repository == 'keymanapp/keyman' || github.event.client_payload.force
runs-on: windows-11-arm
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
ref: '${{ github.event.client_payload.buildSha }}'
- name: Set pending status on PR builds
id: set_status
if: github.event.client_payload.isTestBuild == 'true'
shell: bash
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
repos/$GITHUB_REPOSITORY/statuses/${{ github.event.client_payload.buildSha }} \
-f state='pending' \
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
-f description='Keyman Core - ARM64 test started' \
-f context="$STATUS_CONTEXT"
- name: Report initial npm/node versions
run: |
echo "Initial npm/node versions"
npm -v
node -v
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- uses: actions/setup-node@v6
with:
# This needs to be kept in sync with minimum-versions.sh
node-version: '20.19'
# As of Dec 2025, ngrok not yet supported on ARM Windows,
# google-closure-compiler (and others?) does not support arm64 yet, so
# use the x64 version of node. This is needed to avoid `npm ci` failure,
# even though we don't use ngrok directly; google-closure-compiler is
# used by emscripten
architecture: x64
- name: Report on current environment
shell: bash
run: |
echo "-- Environment --"
echo "pythonLocation=$pythonLocation"
echo "-- Current npm/node versions --"
npm -v
node -v
- name: Setup environment
shell: bash
run: |
# As of Dec 2025, Emscripten does not support Win11 ARM natively
echo "EMSDK_ARCH=x86_64" >> $GITHUB_ENV
echo "EMSDK_KEEP_DOWNLOADS=1" >> $GITHUB_ENV
echo "KEYMAN_USE_EMSDK=1" >> $GITHUB_ENV
echo "PATH=$PATH:$pythonLocation/Scripts" >> $GITHUB_ENV
echo "KEYMAN_CI_SKIP_NVM=1" >> $GITHUB_ENV
- name: Install emscripten
shell: bash
run: |
source resources/build/minimum-versions.inc.sh
mkdir ../emsdk
pushd ../emsdk
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install "${KEYMAN_MIN_VERSION_EMSCRIPTEN}"
./emsdk activate "${KEYMAN_MIN_VERSION_EMSCRIPTEN}"
cd upstream/emscripten
npm install
echo "EMSCRIPTEN_BASE=$(pwd)" >> $GITHUB_ENV
popd
- name: Install meson
shell: bash
run: |
pip3 install --user meson
- name: Run test
shell: bash
run: |
# Run the test
./core/build.sh configure,build,test:arm64
set_status:
name: Set result status on PR builds
needs: [core-arm64-windows-test]
runs-on: windows-11-arm
if: ${{ always() && github.event.client_payload.isTestBuild == 'true' }}
steps:
- name: Set success
if: needs.core-arm64-windows-test.result == 'success'
shell: bash
run: |
echo "RESULT=success" >> $GITHUB_ENV
echo "MSG=Keyman Core ARM64 test succeeded" >> $GITHUB_ENV
- name: Set cancelled
if: needs.core-arm64-windows-test.result == 'cancelled'
shell: bash
run: |
echo "RESULT=error" >> $GITHUB_ENV
echo "MSG=Keyman Core ARM64 test cancelled" >> $GITHUB_ENV
- name: Set failure
if: needs.core-arm64-windows-test.result == 'failure'
shell: bash
run: |
echo "RESULT=failure" >> $GITHUB_ENV
echo "MSG=Keyman Core ARM64 test failed" >> $GITHUB_ENV
- name: Set final status
shell: bash
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
repos/$GITHUB_REPOSITORY/statuses/${{ github.event.client_payload.buildSha }} \
-f state="$RESULT" \
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
-f description="$MSG" \
-f context="$STATUS_CONTEXT"

View file

@ -16,7 +16,7 @@ jobs:
uses: actions/checkout@v4
- name: crowdin action
uses: crowdin/github-action@2.7.0
uses: crowdin/github-action@v2.7.0
with:
upload_sources: true

View file

@ -1,43 +0,0 @@
# Ubuntu Packaging GitHub Action
You can manually trigger a deb-packaging action on GitHub, e.g. to test changes:
- push the changes to your fork of keymanapp/keyman: git push myfork HEAD:master
- make sure you have GHA enabled in the settings of your fork and created an
access token on GitHub
- trigger a build with:
```bash
curl --write-out '\n' --request POST \
--header "Accept: application/vnd.github+json" \
--header "Authorization: token $GITHUB_TOKEN" \
--data "{ \"event_type\": \"deb-pr-packaging: master\", \
\"client_payload\": { \
\"buildSha\": \"$(git rev-parse refs/heads/master)\", \
\"branch\": \"master\", \
\"baseBranch\": \"master\",
\"baseRef\": \"$(git rev-parse refs/heads/master^)\",
\"user\": \"${USER}\",
\"isTestBuild\": \"true\",
\"force\": \"true\"}" \
https://api.github.com/repos/<yourgithubname>/keyman/dispatches
```
To trigger a build for PR #1234 in a branch `pr-1234` this would look similar
to this:
```bash
curl --write-out '\n' --request POST \
--header "Accept: application/vnd.github+json" \
--header "Authorization: token $GITHUB_TOKEN" \
--data "{ \"event_type\": \"deb-pr-packaging: PR #1234\", \
\"client_payload\": { \
\"buildSha\": \"$(git rev-parse refs/heads/pr-1234)\", \
\"branch\": \"pr-1234\", \
\"baseBranch\": \"master\",
\"baseRef\": \"$(git rev-parse refs/heads/master)\",
\"user\": \"${USER}\",
\"isTestBuild\": \"true\",
\"force\": \"true\"}" \
https://api.github.com/repos/<yourgithubname>/keyman/dispatches
```

View file

@ -136,7 +136,7 @@ jobs:
strategy:
fail-fast: true
matrix:
dist: [jammy, noble, plucky, questing]
dist: [jammy, noble, questing]
steps:
- name: Checkout

View file

@ -82,6 +82,8 @@ jobs:
summary += addStatus(o, 'build', status.context, status.state);
} else if(status.context == 'npm pack/publish') {
summary += addStatus(o, 'build', status.context, status.state);
} else if(status.context == 'Keyman Core - ARM64 test') {
summary += addStatus(o, 'build', status.context, status.state);
} else if(status.context == 'check/web/file-size') {
// Ignore check/web/file-size -- we won't block automerge for this at this point
summary += addLog(`Skipping ${status.context}`);
@ -109,9 +111,10 @@ jobs:
const { state, type } = filtered_statuses[context];
if(type == 'unknown') {
// We special-case for unknown status checks, and never permit them
console.error(`An unknown context ${context} was found, cannot calculate build status.`);
// Note: function reduceStatuses() is where new status checks can be added
console.error(`An unknown context "${context}" was found, cannot calculate build status.`);
return [
'error', `An unknown context ${context} was found, cannot calculate build status.`, summary
'error', `An unknown context "${context}" was found, cannot calculate build status.`, summary
];
}
if(type == 'build') {

4
.gitignore vendored
View file

@ -103,8 +103,8 @@
/windows/src/engine/keyman32/*.cod
/windows/src/engine/keyman32/*.pdb
# /engine/keymanx64/
/windows/src/engine/keymanx64/x64
# /engine/keymanhp/
/windows/src/engine/keymanhp/x64
# /engine/kmcomapi/
/windows/src/engine/kmcomapi/kmcomapi.tlb

View file

@ -1,5 +1,117 @@
# Keyman Version History
## 19.0.192 alpha 2026-01-15
* fix(linux): issues when running ./build.sh test:linux (#15434)
## 19.0.191 alpha 2026-01-14
* maint(linux): remove EOL Ubuntu 25.04 Plucky (#15423)
* maint(common): fix build when using different default node version (#15422)
## 19.0.190 alpha 2026-01-14
* Update link to PrimerPrep in step-3.md (#15426)
* chore(common): Update Crowdin strings for Italian (#15418)
* maint(common): Handle custom languages in Crowdin CLI v4 (#15420)
## 19.0.189 alpha 2026-01-12
* maint(common): Update `crowdin.yml` to work with Crowdin CLI 4.0+ (#15407)
## 19.0.188 alpha 2026-01-09
* fix(mac): correct memory width mismatch in keyCodeForChar (#15393)
* docs(common): document `api-verification` GHA (#15410)
## 19.0.187 alpha 2026-01-08
* maint(resources): add new ARM64 test status check to PR build status check (#15409)
* docs(windows): update OS support to include Arm64 Win11 (#15396)
* chore(windows,android): Update Crowdin strings for Portuguese (#15406)
## 19.0.186 alpha 2026-01-07
* maint: add script to report on recent changes to stable release (#15389)
## 19.0.185 alpha 2026-01-06
* chore(web): escape some additional values in TC service messages (#15384)
## 19.0.184 alpha 2025-12-23
* maint(resources): set shell for steps in core-arm64-windows-test.yml (#15387)
* feat(developer): write UTF-8 .kmn file in kmdecomp (#15390)
## 19.0.183 alpha 2025-12-22
* maint(core): remove leading slash on gh api call parameter (#15381)
* maint(core): fix test runner runs-on (#15382)
## 19.0.182 alpha 2025-12-22
* maint(common): Fix crowdin sync version to v2.7.0 (#15373)
* chore(linux): Update keyman-config.pot strings (#15366)
* chore(windows): show architecture in support texteditor (#15378)
## 19.0.181 alpha 2025-12-20
* fix(developer): clear message when selecting custom layer name in touch layout editor (#15371)
* fix(developer): prevent duplicate layer name in Layer Properties dialog (#15372)
## 19.0.180 alpha 2025-12-19
* fix(mac): ensure retry for mac disk detach actually repeats (#15330)
* fix(developer): handle Enter key in dialogs in Touch Layout Editor (#15338)
* chore(windows): fix typo in error message (#15362)
* chore(common): Update crowdin strings for PT (#15368)
## 19.0.179 alpha 2025-12-18
* fix(linux): fix persisting options (#15364)
## 19.0.178 alpha 2025-12-17
* chore(windows): correct kbda1 to kbdth0 in comment in unit test (#15351)
## 19.0.177 alpha 2025-12-16
* feat(windows): report a sentry event when low level hook is reinstalled (#15335)
* chore(linux): add manual test for localization (#15356)
* feat(developer): show keyboard version in web debugger (#15339)
## 19.0.176 alpha 2025-12-13
* chore(windows): remove unused variable (#15334)
## 19.0.175 alpha 2025-12-12
* fix(windows): use Thai Kedmanee instead of Arabic 101 in RightAltEmulationCheck.tests.cpp (#15346)
## 19.0.174 alpha 2025-12-10
* chore(windows): simple bisect utility for checking setup-redist.exe file size (#15322)
## 19.0.173 alpha 2025-12-09
* docs(developer): Clarify keystrokes in Step-1 of tutorial (#15326)
* feat(android): Add Grabbable Bar and settings status for keyboard resizing (#15267)
* chore(linux): Update debian changelog (#15282)
* docs(web): fix typo in osk documentation (#15313)
## 19.0.172 alpha 2025-12-08
* docs(web): add links to next/previous page to web guide (#15311)
* fix(developer): verify project file loaded successfully in analyze (#15318)
## 19.0.171 alpha 2025-12-08
* maint(resources): verify order of builder_describe_internal_dependency (#15257)
* maint(common): use `builder_launch` for child builds (#15258)
* change(windows): Revert "change(windows): include map2pdb generation for relevant Delphi projects" (#15276)
* change(windows): add shortcuts to 'Update Available' dialog (#15280)
* maint(resources): roll back builder_launch for trigger-release-builds.sh (#15316)
## 19.0.170 alpha 2025-12-03
* chore(deps-dev): bump js-yaml from 4.1.0 to 4.1.1 in /resources/build/pr-build-status (#15173)

View file

@ -1 +1 @@
19.0.171
19.0.193

View file

@ -22,32 +22,28 @@ import com.keyman.engine.BaseActivity;
import com.keyman.engine.KMManager;
/**
* Settings menu for adjusting the keyboard height. The value for the current device orientation
* is saved in shared preferences.
* Settings menu for adjusting the keyboard height.
* The value for the current device orientation is saved via KMManager.
*/
public class AdjustKeyboardHeightActivity extends BaseActivity {
private static final String TAG = "AdjustKbdHeight";
public static final String adjustKeyboardHeightKey = "AdjustKeyboardHeight";
private static Button resetButton = null;
private static ImageView sampleKeyboard = null;
// Keeps track of the adjusted keyboard height for saving
private static int currentHeight = 0;
private static ViewGroup.LayoutParams layoutParams;
private Button resetButton;
private ImageView sampleKeyboard;
private TextView percentageDisplay;
private int currentHeight;
private ViewGroup.LayoutParams layoutParams;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context context = this;
setContentView(R.layout.activity_adjust_keyboard_height);
setupEdgeToEdge(R.id.adjust_keyboard_layout);
setupStatusBarColors(R.color.keyman_blue, android.R.color.white);
Toolbar toolbar = (Toolbar) findViewById(R.id.titlebar);
Toolbar toolbar = findViewById(R.id.titlebar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
@ -60,76 +56,162 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.keyman_blue)));
}
TextView adjustKeyboardHeightActivityTitle = (TextView) findViewById(R.id.bar_title);
String titleStr = getString(R.string.adjust_keyboard_height);
TextView adjustKeyboardHeightActivityTitle = findViewById(R.id.bar_title);
adjustKeyboardHeightActivityTitle.setTextColor(ContextCompat.getColor(this, R.color.ms_white));
adjustKeyboardHeightActivityTitle.setText(titleStr);
adjustKeyboardHeightActivityTitle.setText(getString(R.string.adjust_keyboard_height));
sampleKeyboard = findViewById(R.id.sample_keyboard);
percentageDisplay = findViewById(R.id.keyboard_height_percentage);
View resizeHandle = findViewById(R.id.resize_handle);
sampleKeyboard = (ImageView) findViewById(R.id.sample_keyboard);
layoutParams = sampleKeyboard.getLayoutParams();
currentHeight = KMManager.getKeyboardHeight(context);
refreshSampleKeyboard(context);
currentHeight = KMManager.getKeyboardHeight(this);
refreshSampleKeyboard();
resetButton = (Button) findViewById(R.id.reset_to_defaults);
resetButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Clear the keyboard height preferences to reset
KMManager.applyKeyboardHeight(context, KMManager.KeyboardHeight_Reset);
// Restore default height
currentHeight = KMManager.getKeyboardHeight(context);
refreshSampleKeyboard(context);
}
resetButton = findViewById(R.id.reset_to_defaults);
resetButton.setOnClickListener(v -> {
KMManager.applyKeyboardHeight(this, KMManager.KeyboardHeight_Reset);
currentHeight = KMManager.getKeyboardHeight(this);
refreshSampleKeyboard();
});
sampleKeyboard.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
int y = (int)event.getY();
switch(event.getAction()) {
case MotionEvent.ACTION_MOVE:
// Update currentHeight as the user drags (moves)
// Increasing the keyboard height is a negative y
currentHeight -= y;
// Apply lower and upper bounds on currentHeight
int minKeyboardHeight = KMManager.getKeyboardHeightMin(context);
int maxKeyboardHeight = KMManager.getKeyboardHeightMax(context);
currentHeight = Math.max(minKeyboardHeight, currentHeight);
currentHeight = Math.min(maxKeyboardHeight, currentHeight);
refreshSampleKeyboard(context);
break;
case MotionEvent.ACTION_UP:
// Save the currentHeight when the user releases
KMManager.applyKeyboardHeight(context, currentHeight);
break;
}
return true;
View.OnTouchListener touchListener = (view, event) -> {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
view.setPressed(true);
break;
case MotionEvent.ACTION_MOVE:
int[] location = new int[2];
sampleKeyboard.getLocationOnScreen(location);
int viewBottom = location[1] + sampleKeyboard.getHeight();
int touchY = (int) event.getRawY();
currentHeight = calculateKeyboardHeightFromTouch(touchY, viewBottom);
refreshSampleKeyboard();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
view.setPressed(false);
KMManager.applyKeyboardHeight(this, currentHeight);
break;
}
});
return true;
};
resizeHandle.setOnTouchListener(touchListener);
sampleKeyboard.setOnTouchListener(touchListener);
}
/**
* Refresh the layout for the sample keyboard
* @param context
* Refresh the layout for the sample keyboard and update percentage display.
*/
private void refreshSampleKeyboard(Context context) {
layoutParams.height = currentHeight;
sampleKeyboard.setLayoutParams(layoutParams);
private void refreshSampleKeyboard() {
if (layoutParams != null && sampleKeyboard != null) {
layoutParams.height = currentHeight;
sampleKeyboard.requestLayout();
if (percentageDisplay != null) {
percentageDisplay.setText(createLiveKeyboardHeightString());
}
}
}
/**
* Calculate percentage from height and default height.
* @param height Current height
* @param defaultHeight Default height
* @return Percentage rounded to nearest integer
*/
private static int calculatePercentage(int height, int defaultHeight) {
if (defaultHeight == 0 || height == 0) {
return 100;
}
return (int) Math.round((double) height / defaultHeight * 100);
}
/**
* Create a string showing the keyboard height as percentages for both orientations.
* @param context Context
* @return String in format "100% Portrait | 100% Landscape"
*/
public static String createKeyboardHeightString(Context context) {
int portraitHeight = KMManager.getKeyboardHeight(context, Configuration.ORIENTATION_PORTRAIT);
int landscapeHeight = KMManager.getKeyboardHeight(context, Configuration.ORIENTATION_LANDSCAPE);
int portraitDefault = KMManager.getDefaultKeyboardHeight(Configuration.ORIENTATION_PORTRAIT);
int landscapeDefault = KMManager.getDefaultKeyboardHeight(Configuration.ORIENTATION_LANDSCAPE);
int portraitPercent = calculatePercentage(portraitHeight, portraitDefault);
int landscapePercent = calculatePercentage(landscapeHeight, landscapeDefault);
return context.getString(R.string.keyboard_height_format, portraitPercent, landscapePercent);
}
/**
* Calculate keyboard height from touch Y coordinate and clamp
* within min-max bounds.
* @param touchY Touch Y coordinate in screen coordinates
* @param viewBottom Bottom Y coordinate of keyboard view
* @return Keyboard height in pixels, clamped to min/max bounds
*/
private int calculateKeyboardHeightFromTouch(int touchY, int viewBottom) {
int height = viewBottom - touchY;
int minKeyboardHeight = KMManager.getKeyboardHeightMin(this);
int maxKeyboardHeight = KMManager.getKeyboardHeightMax(this);
return Math.max(minKeyboardHeight, Math.min(maxKeyboardHeight, height));
}
/**
* Create a string showing keyboard height percentages for both orientations,
* using the current (unsaved) height for the active orientation.
* @return String in format "100% Portrait | 100% Landscape"
*/
private String createLiveKeyboardHeightString() {
int currentOrientation = KMManager.getOrientation(this);
int portraitDefault = KMManager.getDefaultKeyboardHeight(Configuration.ORIENTATION_PORTRAIT);
int landscapeDefault = KMManager.getDefaultKeyboardHeight(Configuration.ORIENTATION_LANDSCAPE);
int portraitHeight;
int landscapeHeight;
if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
portraitHeight = currentHeight;
landscapeHeight = KMManager.getKeyboardHeight(this, Configuration.ORIENTATION_LANDSCAPE);
} else {
landscapeHeight = currentHeight;
portraitHeight = KMManager.getKeyboardHeight(this, Configuration.ORIENTATION_PORTRAIT);
}
int portraitPercent = calculatePercentage(portraitHeight, portraitDefault);
int landscapePercent = calculatePercentage(landscapeHeight, landscapeDefault);
return getString(R.string.keyboard_height_format, portraitPercent, landscapePercent);
}
@Override
protected void onPause() {
super.onPause();
// Ensure height is saved even if user switches tasks or navigates away abnormally
// This prevents the touch zone from being out of sync with the keyboard visual
if (currentHeight > 0) {
KMManager.applyKeyboardHeight(this, currentHeight);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// IMPORTANT: Apply current height BEFORE switching orientations
// This ensures the old orientation's height is saved before loading the new one
if (currentHeight > 0) {
KMManager.applyKeyboardHeight(this, currentHeight);
}
layoutParams = sampleKeyboard.getLayoutParams();
// When the user rotates the device, restore currentHeight
// When the user rotates the device, restore currentHeight for the new orientation
currentHeight = KMManager.getKeyboardHeight(this);
refreshSampleKeyboard(this);
refreshSampleKeyboard();
}
@Override

View file

@ -106,6 +106,7 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat {
adjustKeyboardHeight.setKey(AdjustKeyboardHeightActivity.adjustKeyboardHeightKey);
adjustKeyboardHeight.setTitle(getString(R.string.adjust_keyboard_height));
adjustKeyboardHeight.setWidgetLayoutResource(R.layout.preference_height_icon_layout);
adjustKeyboardHeight.setSummary(AdjustKeyboardHeightActivity.createKeyboardHeightString(context));
Intent adjustKeyboardHeightIntent = new Intent(context, AdjustKeyboardHeightActivity.class);
adjustKeyboardHeight.setIntent(adjustKeyboardHeightIntent);
@ -268,5 +269,7 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat {
// Update the language / keyboard count when we return to this menu from deeper levels.
languagesPreference.setTitle(getInstalledLanguagesText());
adjustKeyboardHeight.setSummary(AdjustKeyboardHeightActivity.createKeyboardHeightString(context));
}
}

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/ms_white"
android:pathData="M12,20 L4,8 L20,8 Z" />
</vector>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/ms_white"
android:pathData="M12,4 L4,16 L20,16 Z" />
</vector>

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Resize handle bar background with grip lines -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Base background with Keyman blue -->
<item>
<shape android:shape="rectangle">
<solid android:color="@color/keyman_blue" />
<corners
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
</shape>
</item>
<!-- Grip indicator - three horizontal lines -->
<item
android:gravity="center"
android:top="12dp"
android:bottom="12dp">
<layer-list>
<item android:top="0dp" android:bottom="10dp">
<shape android:shape="rectangle">
<solid android:color="@color/ms_white" />
<corners android:radius="1dp" />
<size android:width="40dp" android:height="3dp" />
</shape>
</item>
<item android:top="6dp" android:bottom="6dp">
<shape android:shape="rectangle">
<solid android:color="@color/ms_white" />
<corners android:radius="1dp" />
<size android:width="40dp" android:height="3dp" />
</shape>
</item>
<item android:top="10dp" android:bottom="0dp">
<shape android:shape="rectangle">
<solid android:color="@color/ms_white" />
<corners android:radius="1dp" />
<size android:width="40dp" android:height="3dp" />
</shape>
</item>
</layer-list>
</item>
</layer-list>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Resize handle bar with grip lines and touch feedback -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Pressed state - solid darker background -->
<item android:state_pressed="true">
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="#0E5196" />
<corners
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
</shape>
</item>
<item
android:width="40dp"
android:height="4dp"
android:gravity="center">
<shape android:shape="rectangle">
<solid android:color="@color/ms_white" />
<corners android:radius="2dp" />
</shape>
</item>
</layer-list>
</item>
<!-- Default state - gradient background with grip lines -->
<item android:drawable="@drawable/resize_handle_background" />
</selector>

View file

@ -10,32 +10,22 @@
<include layout="@layout/titlebar" />
<TextView
android:id="@+id/drag_the_keyboard"
android:id="@+id/adjust_instructions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/titlebar"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:text="@string/drag_the_keyboard"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_marginTop="8dp"
android:text="@string/adjust_keyboard_instructions"
android:textSize="@dimen/adjust_keyboard_height_label_textsize"
app:layout_constraintTop_toBottomOf="@id/titlebar" />
<TextView
android:id="@+id/rotate_the_device"
android:layout_below="@id/drag_the_keyboard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:text="@string/rotate_the_device"
android:textSize="@dimen/adjust_keyboard_height_label_textsize"
app:layout_constraintTop_toBottomOf="@id/drag_the_keyboard" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/button_layout"
android:orientation="horizontal"
android:layout_below="@id/rotate_the_device"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/rotate_the_device">
app:layout_constraintTop_toBottomOf="@id/adjust_instructions">
<Button
android:id="@+id/reset_to_defaults"
@ -57,6 +47,70 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Percentage Display -->
<TextView
android:id="@+id/keyboard_height_percentage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="100% Portrait | 100% Landscape"
app:layout_constraintTop_toBottomOf="@id/button_layout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Grabbable Resize Handle Bar -->
<LinearLayout
android:id="@+id/resize_handle"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/resize_handle_bar"
android:orientation="horizontal"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:contentDescription="@string/adjust_keyboard_instructions"
app:layout_constraintBottom_toTopOf="@id/sample_keyboard"
app:layout_constraintStart_toStartOf="parent">
<!-- Up arrow on left -->
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="16dp"
android:src="@drawable/ic_arrow_up"
android:contentDescription="Resize up" />
<!-- Spacer to center -->
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<!-- Center grip lines (visual from background drawable) -->
<View
android:layout_width="60dp"
android:layout_height="match_parent" />
<!-- Spacer to right -->
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<!-- Down arrow on right -->
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_arrow_down"
android:contentDescription="Resize down" />
</LinearLayout>
<!-- Resizable keyboard "image -->
<ImageView
android:id="@+id/sample_keyboard"
@ -65,15 +119,7 @@
android:contentDescription="@string/adjust_keyboard_height"
android:scaleType="fitXY"
android:src="@drawable/blank_osk"
android:background="@drawable/dash_border"
android:layout_alignParentBottom="true"
android:paddingStart="@dimen/blank_osk_padding"
android:paddingEnd="@dimen/blank_osk_padding"
android:paddingTop="@dimen/blank_osk_padding"
android:paddingBottom="@dimen/blank_osk_padding"
app:layout_constraintTop_toBottomOf="@id/button_layout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="1.0" />
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -116,9 +116,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">ሁሉም ቋንቋዎች ቀደም ሲል ተጭኗል</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">የፊደል ገበታ ሰሌዳውን በመጎተት ቁመቱን አስተካክል</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">ዲቫይሱን በማሽከርከር ፖርትሬቱንና ላንድስኬፑን አስተካክል</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">የፊደል ገበታ ሰሌዳውን በመጎተት ቁመቱን አስተካክል ዲቫይሱን በማሽከርከር ፖርትሬቱንና ላንድስኬፑን አስተካክል</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">ወደ ቀደመው ሴቲንግ መልስ</string>
<!-- Context: Keyman Web Browser -->

View file

@ -122,9 +122,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">كل اللغات مثبتة مسبقا</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">اسحب لوحة المفاتيح لتغيير مدى ارتفاعها</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">دور الجهاز لضبط الوضع العمودي والوضع الأفقي</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">اسحب لوحة المفاتيح لتغيير مدى ارتفاعها. دور الجهاز لضبط الوضع العمودي والوضع الأفقي.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">إعادة ضبط الافتراضيات</string>
<!-- Context: Keyman Web Browser -->

View file

@ -114,9 +114,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Bütün dillər artıq quraşdırılıb</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Hündürlüyünün ölcüsü tənzimləmək üçün klaviaturanı dartın</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Portret və landşaft tənzimləmək üçün cihazı çevirin</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Hündürlüyünün ölcüsü tənzimləmək üçün klaviaturanı dartın. Portret və landşaft tənzimləmək üçün cihazı çevirin.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">İlkin vəziyyətinə qaytar</string>
<!-- Context: Keyman Web Browser -->

View file

@ -120,9 +120,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Ὅλες οἱ γλῶσσες ἔχουν ἤδη ἐγκατασταθεῖ</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Σύρετε τὸ πληκτρολόγιο γιὰ νὰ ἀλλάξετε τὸ ὕψος του</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Περιστρέψτε τὴν συσκευὴ γιὰ προσαρμογὴ τοῦ ὕψους σὲ λειτουργία πορτραίτου καὶ τοπίου</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Σύρετε τὸ πληκτρολόγιο γιὰ νὰ ἀλλάξετε τὸ ὕψος του. Περιστρέψτε τὴν συσκευὴ γιὰ προσαρμογὴ τοῦ ὕψους σὲ λειτουργία πορτραίτου καὶ τοπίου.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Ἐπαναφέρετε τὶς προεπιλεγμένες ρυθμίσεις</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -120,9 +120,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Ya están instalados todos los idiomas</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Arrastra el teclado para ajustar la altura</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Rota el dispositivo para ajustar el modo vertical y horizontal</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Arrastra el teclado para ajustar la altura. Rota el dispositivo para ajustar el modo vertical y horizontal.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Restaurar valores predeterminados</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -117,9 +117,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Luggat chatta dakhalo</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Ajubdal keyboard ley badalan tula</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Barrumal shu\'ul ley badalan shaba binshaf</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Ajubdal keyboard ley badalan tula. Barrumal shu\'ul ley badalan shaba binshaf.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Eingalab ley shaba gabul</string>
<!-- Context: Keyman Web Browser -->

View file

@ -114,9 +114,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Hulfur mnyayeri natǝ mdǝku kurtǝ ka hara instal ɗa</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Ndǝkǝr keyboard kamnyar jaktǝ wala kǝmta saɓǝlkur ni</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Shinar waya wala hansetu ni kamnyar katsa nzi thlat-thlata wala peri-periari</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Ndǝkǝr keyboard kamnyar jaktǝ wala kǝmta saɓǝlkur ni. Shinar waya wala hansetu ni kamnyar katsa nzi thlat-thlata wala peri-periari.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Kalaktǝni katsa ni tsu apa tǝ mdǝ nam ni</string>
<!-- Context: Keyman Web Browser -->

View file

@ -117,9 +117,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Shanga nyayere ndǝ kurtǝ vu tǝdar</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Ndǝrti kibod akuya ka gǝ kǝnta dzugamkurir ko saɓǝlkur su</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Mwari aka sǝr ʻya su akuyaka gǝ dzuguti njaiyir lanskep</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Ndǝrti kibod akuya ka gǝ kǝnta dzugamkurir ko saɓǝlkur su. Mwari aka sǝr ʻya su akuyaka gǝ dzuguti njaiyir lanskep.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Ɓǝla ʻyati tǝni apa Waci</string>
<!-- Context: Keyman Web Browser -->

View file

@ -122,9 +122,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Všechny jazyky jsou již nainstalovány</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Přetažením klávesnice změníte výšku</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Otočit zařízení pro nastavení na výšku a na šířku</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Přetažením klávesnice změníte výšku. Otočit zařízení pro nastavení na výšku a na šířku.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Obnovit výchozí nastavení</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -118,9 +118,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Alle Sprachen bereits installiert</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Ziehen Sie die Tastatur, um die Höhe zu ändern</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Drehen Sie das Gerät um Hoch- und Querformat anzupassen</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Ziehen Sie die Tastatur, um die Höhe zu ändern. Drehen Sie das Gerät um Hoch- und Querformat anzupassen.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Einstellungen auf Standard zurücksetzen</string>
<!-- Context: Keyman Web Browser -->

View file

@ -120,9 +120,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Todos los idiomas ya están instalados</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Mueve el teclado para reajustar la altura</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Rotar el dispositivo para ajustar a modo vertical u horizontal</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Mueve el teclado para reajustar la altura. Rotar el dispositivo para ajustar a modo vertical u horizontal.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Restablecer valores predeterminados</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -114,9 +114,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Ɗemngal man fuu arti wa`inni</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Dasa kibod man ngam de`itina juutugo</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Waylutu na`ura man ngam a` de`itina dow bee les</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Dasa kibod man ngam de`itina juutugo. Waylutu na`ura man ngam a` de`itina dow bee les.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Lornu ɗum ko naftirta tum</string>
<!-- Context: Keyman Web Browser -->

View file

@ -115,9 +115,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Ɗemɗe fof aafaama kisa</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Daas tappirde ndee ngam waylude tooweendi</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Yiiltu kaɓirgol ngol ngam fotndude naddaro e leddaro</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Daas tappirde ndee ngam waylude tooweendi. Yiiltu kaɓirgol ngol ngam fotndude naddaro e leddaro.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Artir e Goowaaɗe</string>
<!-- Context: Keyman Web Browser -->

View file

@ -118,9 +118,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Toutes les langues de cet ensemble sont déjà installées</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Faites glisser le clavier pour redimensionner la hauteur</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Faire pivoter l\'appareil pour ajuster le portrait et le paysage</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Faites glisser le clavier pour redimensionner la hauteur. Faire pivoter l\'appareil pour ajuster le portrait et le paysage.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Réinitialiser aux valeurs par défaut</string>
<!-- Context: Keyman Web Browser -->

View file

@ -114,9 +114,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">An riga da an shigar da dukkanin yarukan</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Danne madanni domin sake girman</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Juya na\'urar domin daidaita hoto da gyara shi</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Danne madanni domin sake girman. Juya na\'urar domin daidaita hoto da gyara shi.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Gyara saiti zuwa yadda ya dace</string>
<!-- Context: Keyman Web Browser -->

View file

@ -115,9 +115,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Sma gwaɗaha luwunda falo</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">An tiɗat keyboard ka virata mbakat fiwuku</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Awava tina ngana ka gulat foto nda plavant bugo</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">An tiɗat keyboard ka virata mbakat fiwuku. Awava tina ngana ka gulat foto nda plavant bugo.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Virata magat ina kol ɗughwana</string>
<!-- Context: Keyman Web Browser -->

View file

@ -113,9 +113,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Semua bahasa telah terpasang</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Drag the keyboard to resize the height</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Rotate the device to adjust portrait and landscape</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Drag the keyboard to resize the height. Rotate the device to adjust portrait and landscape.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Reset to Defaults</string>
<!-- Context: Keyman Web Browser -->

View file

@ -19,8 +19,9 @@
<string name="action_install_updates" comment="Menu notification that keyboard or dictionary updates available">Installa Aggiornamenti</string>
<!-- Context: Title -->
<string name="title_version" comment="Title of Keyman for Android version">Versione: %1$s</string>
<!-- Context: Text label when old Chrome version installed -->
<!-- Context: Text label when old Chrome version installed. Label replaced in Keyman 19.0 -->
<string name="text_require_chrome_57" comment="Banner text when old version of Chrome is installed"> Keyman richiede la versione 57 di Chrome o superiore.</string>
<string name="text_require_chrome_version" comment="Banner text when old version of Chrome is installed"> Keyman richiede Chrome versione %1$s o superiore.</string>
<!-- Context: Button label -->
<string name="button_update_chrome" comment="Prompt to upgrade Chrome in the Play Store">Aggiorna Chrome</string>
<!-- Context: Textfield prompt (&#8230; is the ellipsis character "...") -->
@ -87,6 +88,10 @@
<string name="spacebar_caption_hint_language_keyboard" comment="Spacebar caption hint - language + keyboard">Lingua e tastiera nella barra spaziatrice</string>
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
<string name="spacebar_caption_hint_blank" comment="Spacebar caption hint - blank">Non mostrare la didascalia sulla barra spaziatrice</string>
<!-- Context: Keyman Settings menu / Show OSK with Physical Keyboard -->
<string name="show_osk" comment="show OSK when physical keyboard is connected">Mostra tastiera a schermo</string>
<!-- Context: Keyman Settings menu / Show OSK with Physical Keyboard hint -->
<string name="show_osk_hint" comment="When physical keyboard is connected">Quando la tastiera fisica è connessa</string>
<!-- Context: Keyman Settings menu / Haptic feedback -->
<string name="haptic_feedback" comment="haptic feedback on key press">Vibra durante la digitazione</string>
<!-- Context: Keyman Settings menu. Removed in Keyman 18 -->
@ -120,11 +125,11 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Tutte le lingue già installate</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Trascina la tastiera per ridimensionare l\'altezza</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Ruota il dispositivo per regolare verticale e orizzontale</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Trascina la tastiera per ridimensionarne l\'altezza. Ruota il dispositivo per regolare verticale e orizzontale.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Ripristina impostazioni predefinite</string>
<!-- Context: Keyboard height display format. %1$d = portrait percentage, %2$d = landscape percentage -->
<string name="keyboard_height_format" comment="Format for displaying keyboard height percentages">Altezza %1$d%% | Larghezza %2$d%%</string>
<!-- Context: Adjust Longpress Delay Time menu -->
<string name="longpress_delay_time" comment="Current longpress delay time (seconds)">Tempo ritardo: %1$.1f secondi</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -119,9 +119,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">ភាសា​ទាំង​អស់​ដែល​បាន​ដំឡើង​ហើយ</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">ទាញក្ដារចុចដើម្បីកែកម្ពស់</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">បង្វិលឧបករណ៍ដើម្បីកែបញ្ឈ និងផ្ដេក</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">ទាញក្ដារចុចដើម្បីកែកម្ពស់ បង្វិលឧបករណ៍ដើម្បីកែបញ្ឈ និងផ្ដេក</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">ប្ដូរ​កំណត់​ទៅលំនាំដើម</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -118,9 +118,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">ಎಲ್ಲಾ ಭಾಷೆಗಳನ್ನು ಈಗಾಗಲೇ ಸ್ಥಾಪಿಸಲಾಗಿದೆ</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">ಎತ್ತರವನ್ನು ಬದಲಾಯಿಸಲು ಕೀಲಿಮಣೆಯನ್ನು ಎಳೆಯಿರಿ</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">ಪೋರ್ಟ್ರೇಟ್ ಮತ್ತು ಲ್ಯಾಂಡ್ಸ್ಕೇಪ್ ಹೊಂದಿಸಲು ಸಾಧನವನ್ನು ತಿರುಗಿಸಿ</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">ಎತ್ತರವನ್ನು ಬದಲಾಯಿಸಲು ಕೀಲಿಮಣೆಯನ್ನು ಎಳೆಯಿರಿ. ಪೋರ್ಟ್ರೇಟ್ ಮತ್ತು ಲ್ಯಾಂಡ್ಸ್ಕೇಪ್ ಹೊಂದಿಸಲು ಸಾಧನವನ್ನು ತಿರುಗಿಸಿ.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">ಡೀಫಾಲ್ಟ್ ಮರುಹೊಂದಿಸಿ</string>
<!-- Context: Keyman Web Browser -->

View file

@ -114,9 +114,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Tǝlam samma ikke</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Keyboard dǝ girne datǝnzǝ dǝ fulutǝ ro</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Device dǝ suwarne daatanzǝ daata dǝa kuru baatanzǝ dǝa</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Keyboard dǝ girne datǝnzǝ dǝ fulutǝ ro. Device dǝ suwarne daatanzǝ daata dǝa kuru baatanzǝ dǝa.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Bǝlin sarro waltǝne setinne</string>
<!-- Context: Keyman Web Browser -->

View file

@ -114,9 +114,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Baɗumma naraha na an fa amikwa ŋanna</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Piya keyboard gé fare tsa ne adaliya</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Mbeɗanahe nja nawura ŋanna gé portrait antara landscape</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Piya keyboard gé fare tsa ne adaliya. Mbeɗanahe nja nawura ŋanna gé portrait antara landscape.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Reset to Defaults</string>
<!-- Context: Keyman Web Browser -->

View file

@ -120,9 +120,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">စုတ်ဘာသာသီုဖအိုတ်တုဲ</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">သ္ဂောံချိၚ်သမၠုၚ် ကဳဗုဒ်ဂှ် ဂြဲညိ</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">ဂွံချိၚ် လံက်သတိက် လံက်ဇမၠိၚ်ဂှ် ဗဂေတ်ကဵုစက်ပိုဲညိ။</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">သ္ဂောံချိၚ်သမၠုၚ် ကဳဗုဒ်ဂှ် ဂြဲညိ ဂွံချိၚ် လံက်သတိက် လံက်ဇမၠိၚ်ဂှ် ဗဂေတ်ကဵုစက်ပိုဲညိ။</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">ကလေၚ်သ္ပနူပကတိ</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -114,9 +114,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Ca ŋya yer kuku du mji akuya installed</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Cina keyboard gadibar ngilaba dzigamkur ari</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Shina su ari ga ngilaba dzigamkur baɗa ŋga ari</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Cina keyboard gadibar ngilaba dzigamkur ari. Shina su ari ga ngilaba dzigamkur baɗa ŋga ari.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Iri ga munagu alu lagu ginda nur dang</string>
<!-- Context: Keyman Web Browser -->

View file

@ -114,9 +114,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Alle talen zijn al geïnstalleerd</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Sleep het toetsenbord om de hoogte aan te passen</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Draai het apparaat om portret en liggend aan te passen</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Sleep het toetsenbord om de hoogte aan te passen. Draai het apparaat om portret en liggend aan te passen.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Standaardinstellingen herstellen</string>
<!-- Context: Keyman Web Browser -->

View file

@ -116,9 +116,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Wszystkie języki są już zainstalowane</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Przeciągnij klawiaturę, aby zmienić wysokość</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Obróć urządzenie, aby dostosować pionowo i poziomo</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Przeciągnij klawiaturę, aby zmienić wysokość. Obróć urządzenie, aby dostosować pionowo i poziomo.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Przywróć domyślne</string>
<!-- Context: Keyman Web Browser -->

View file

@ -19,8 +19,9 @@
<string name="action_install_updates" comment="Menu notification that keyboard or dictionary updates available">Instalar Atualizações</string>
<!-- Context: Title -->
<string name="title_version" comment="Title of Keyman for Android version">Versão: %1$s</string>
<!-- Context: Text label when old Chrome version installed -->
<!-- Context: Text label when old Chrome version installed. Label replaced in Keyman 19.0 -->
<string name="text_require_chrome_57" comment="Banner text when old version of Chrome is installed"> O Keyman requer a versão 57 ou mais recente.</string>
<string name="text_require_chrome_version" comment="Banner text when old version of Chrome is installed"> O Keyman requer a versão Chrome %1$s ou mais recente.</string>
<!-- Context: Button label -->
<string name="button_update_chrome" comment="Prompt to upgrade Chrome in the Play Store">Atualizar Chrome</string>
<!-- Context: Textfield prompt (&#8230; is the ellipsis character "...") -->
@ -87,6 +88,10 @@
<string name="spacebar_caption_hint_language_keyboard" comment="Spacebar caption hint - language + keyboard">Idioma e teclado na barra de espaço</string>
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
<string name="spacebar_caption_hint_blank" comment="Spacebar caption hint - blank">Não mostrar legenda na barra de espaço</string>
<!-- Context: Keyman Settings menu / Show OSK with Physical Keyboard -->
<string name="show_osk" comment="show OSK when physical keyboard is connected">Mostrar Teclado no Ecrã</string>
<!-- Context: Keyman Settings menu / Show OSK with Physical Keyboard hint -->
<string name="show_osk_hint" comment="When physical keyboard is connected">Quando o teclado físico é conectado</string>
<!-- Context: Keyman Settings menu / Haptic feedback -->
<string name="haptic_feedback" comment="haptic feedback on key press">Vibrar ao tocar</string>
<!-- Context: Keyman Settings menu. Removed in Keyman 18 -->
@ -120,11 +125,11 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Todos os idiomas já instalados</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Arraste o teclado para redimensionar a altura</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Gire o dispositivo para ajustar o retrato e a paisagem</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Arraste o teclado para redimensionar a altura. Gire o dispositivo para ajustar os modos retrato e paisagem.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Restaurar padrões</string>
<!-- Context: Keyboard height display format. %1$d = portrait percentage, %2$d = landscape percentage -->
<string name="keyboard_height_format" comment="Format for displaying keyboard height percentages">%1$d%% Modo Retrato %2$d%% Modo Paisagem</string>
<!-- Context: Adjust Longpress Delay Time menu -->
<string name="longpress_delay_time" comment="Current longpress delay time (seconds)">Tempo de atraso: %1$.1f segundos</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -117,9 +117,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Все языки уже установлены</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Перетащите клавиатуру для изменения высоты</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Повернуть устройство для настройки портрета и ландшафта</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Перетащите клавиатуру для изменения высоты. Повернуть устройство для настройки портрета и ландшафта.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Сброс по умолчанию</string>
<!-- Context: Keyman Web Browser -->

View file

@ -115,9 +115,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Alla språk är redan installerade</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Dra tangentbordet för att ändra storlek på höjden</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Rotera enheten för att justera stående och liggande</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Dra tangentbordet för att ändra storlek på höjden. Rotera enheten för att justera stående och liggande.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Återställ till standard</string>
<!-- Context: Keyman Web Browser -->

View file

@ -117,9 +117,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Всі мови вже встановлені</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Перетягніть клавіатуру, щоб змінити розмір висоти</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Поверніть пристрій, щоб змінити портретну та альбомну орієнтацію</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Перетягніть клавіатуру, щоб змінити розмір висоти. Поверніть пристрій, щоб змінити портретну та альбомну орієнтацію.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Відновити параметри за замовчуванням</string>
<!-- Context: Keyman Web Browser -->

View file

@ -119,9 +119,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Tất cả ngôn ngữ đã được cài đặt rồi</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Kéo bàn phím để điều chỉnh độ cao</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Xoay thiết bị để điều chỉnh độ ngang độ dọc</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Kéo bàn phím để điều chỉnh độ cao. Xoay thiết bị để điều chỉnh độ ngang độ dọc.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Khôi phục mặc định</string>
<!-- Context: Adjust Longpress Delay Time menu -->

View file

@ -115,9 +115,7 @@
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">所有语言已被安装</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">拖动键盘以调整高度</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">旋转设备以调整横竖屏模式</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">拖动键盘以调整高度. 旋转设备以调整横竖屏模式.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">重置为默认值</string>
<!-- Context: Keyman Web Browser -->

View file

@ -201,14 +201,14 @@
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">All languages already installed</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Drag the keyboard to resize the height</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Rotate the device to adjust portrait and landscape</string>
<string name="adjust_keyboard_instructions" comment="Instructions for adjusting keyboard height">Drag the keyboard to resize the height. Rotate the device to adjust portrait and landscape.</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Reset to Defaults</string>
<!-- Context: Keyboard height display format. %1$d = portrait percentage, %2$d = landscape percentage -->
<string name="keyboard_height_format" comment="Format for displaying keyboard height percentages">%1$d%% Portrait | %2$d%% Landscape</string>
<!-- Context: Adjust Longpress Delay Time menu -->
<string name="longpress_delay_time" comment="Current longpress delay time (seconds)">Delay Time: %1$.1f seconds</string>

View file

@ -82,6 +82,14 @@
<string name="fatal_keyboard_error" comment="Fatal keyboard error (keyboard ID::packageID for language). Will load default keyboard"> Erro fatal de teclado com %1$s:%2$s para %3$s idioma. Carregando o teclado padrão.</string>
<!-- Context: Fatal keyboard error. -->
<string name="fatal_keyboard_error_short" comment="Error in keyboard (keyboard ID::packageID for language)."> Erro no teclado %1$s:%2$s para %3$s idioma.</string>
<!-- Context: Alert Dialog body: System WebView not installed -->
<string name="body_install_webview" comment="Notification when WebView not installed"> Keyman requer que o WebView seja instalado.\"</string>
<!-- Context: Alert Dialog body: System WebView installed but not enabled -->
<string name="body_enable_webview" comment="Notification when WebView installed but not enabled"> Keyman requer que o WebView seja ativado.\"</string>
<!-- Context Button label: Install WebView -->
<string name="label_install_webview" comment="Button label to install webview">Instalar WebView</string>
<!-- Context Button label: Enable WebView -->
<string name="label_enable_webview" comment="Button label to enable webview">Ativar WebView</string>
<!-- Context: Query for associated dictionary -->
<string name="query_associated_model" comment="Check if there's an available dictionary to download">Verificando o download do dicionário associado</string>
<string name="cannot_query_associated_model" comment="Cannot reach server to check if there's an available dictionary to download">A ligação ao servidor do Keyman para verificar dicionários para descarregar falhou</string>
@ -115,6 +123,8 @@
<string name="failed_to_retrieve_file" comment="Failed to retrieve downloaded file">Falha ao recuperar o arquivo baixado</string>
<!-- Context: General Updates -->
<string name="update_check_unavailable" comment="Error message when a Keyman server can't be reached">Falha ao acessar o servidor!</string>
<!-- Context: Update-check failure notification -->
<string name="update_check_download_manager_disabled" comment="Notification that a system service needed for updates is disabled">Gerenciador de Downloads desativado - não é possível verificar atualizações</string>
<!-- Context: General Updates -->
<string name="update_check_current" comment="Notification that all resources are up to date">"Todos os recursos estão atualizados!"</string>
<!-- Context: General Updates -->
@ -138,10 +148,10 @@
<!-- Context: Language Settings menu strings. Removed in Keyman 18 -->
<string name="enable_predictions" comment="Enable predictions from the suggestion banner">Habilitar previsões</string>
<!-- Context: Language Settings menu strings - radio buttons -->
<string name="suggestions_radio_0" comment="Predictions and corrections disabled">Disable suggestions</string>
<string name="suggestions_radio_1" comment="Suggestions Enabled: Predictions with no corrections">Predictions only</string>
<string name="suggestions_radio_2" comment="Suggestions Enabled: Predictions with corrections">Predictions with corrections</string>
<string name="suggestions_radio_3" comment="Suggestions Enabled: Predictions with auto-corrections">Predictions with auto-corrections</string>
<string name="suggestions_radio_0" comment="Predictions and corrections disabled">Desativar sugestões</string>
<string name="suggestions_radio_1" comment="Suggestions Enabled: Predictions with no corrections">Apenas previsões</string>
<string name="suggestions_radio_2" comment="Suggestions Enabled: Predictions with corrections">Previsões com correções</string>
<string name="suggestions_radio_3" comment="Suggestions Enabled: Predictions with auto-corrections">Previsões com correções automáticas</string>
<!-- Context: Language Settings menu strings -->
<string name="model_label">Dicionário</string>
<plurals name="model_count">

View file

@ -26,7 +26,10 @@ export default function teamcityReporter({ name="Web Test Runner JavaScript test
.replace(/\|/g, '||')
.replace(/\[/g, '|[')
.replace(/\]/g, '|]')
.replace(/\'/g, '|\'');
.replace(/\'/g, '|\'')
.replace(/\n/g, '|n')
.replace(/\r/g, '|r')
.replace(/[\u0080-\uFFFF]/g, c => `|0x${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
}
const e = tcReportEscaping;
@ -179,4 +182,4 @@ export default function teamcityReporter({ name="Web Test Runner JavaScript test
};
return reporter;
}
}

View file

@ -8,6 +8,7 @@ if "%1"=="" goto help
if "%1"=="all" goto all
if "%1"=="x86" goto build
if "%1"=="x64" goto build
if "%1"=="arm64" goto build
echo "Invalid parameter."
goto help
@ -15,9 +16,9 @@ goto help
rem ----------------------------------
:help
echo Usage: %0 x86^|x64^|all debug^|release [configure] [build] [test] [additional params for meson/ninja]
echo Usage: %0 x86^|x64^|arm64^|all debug^|release [configure] [build] [test] [additional params for meson/ninja]
echo or
echo Usage: %0 x86^|x64 -c
echo Usage: %0 x86^|x64^|arm64^ -c
echo -c will leave your environment configured for Visual Studio for selected platform.
echo.
echo Otherwise, %0 is intended to be used by build.sh, not directly.
@ -35,17 +36,37 @@ cmd /c build.bat x86 %2 %3 %4 %5 %6 %7 %8 %9 || exit !errorlevel!
cd %KEYMAN_ROOT%\core
cmd /c build.bat x64 %2 %3 %4 %5 %6 %7 %8 %9 || exit !errorlevel!
cd %KEYMAN_ROOT%\core
cmd /c build.bat arm64 %2 %3 %4 %5 %6 %7 %8 %9 || exit !errorlevel!
goto :eof
rem ----------------------------------
:build
set "HOST_ARCH=%PROCESSOR_ARCHITECTURE%"
rem Map Windows arch strings to VsDevCmd expected values
if /I "%HOST_ARCH%"=="AMD64" set "HOST_ARCH=amd64"
if /I "%HOST_ARCH%"=="x86" set "HOST_ARCH=x86"
if /I "%HOST_ARCH%"=="ARM64" set "HOST_ARCH=arm64"
set ARCH=%1
shift
if "%1"=="-c" goto :setup
rem Initialize MESON_CROSS_FILE as empty
set "MESON_CROSS_FILE="
rem Check if cross file exists (using %~dp0 for script directory)
if exist "%~dp0cross-%ARCH%.build" (
echo [DEBUG] Using cross file cross-%ARCH%.build
set "MESON_CROSS_FILE=--cross-file cross-%ARCH%.build"
)
echo === Locating Visual Studio ===
rem From https://github.com/microsoft/vswhere
@ -65,8 +86,7 @@ if not exist "!VsDevCmd_Path!" (
echo === Configuring VC++ ===
set VSCMD_SKIP_SENDTELEMETRY=1
call "!VsDevCmd_Path!" -arch=!ARCH! -no_logo -startdir=none || exit !errorlevel!
call "!VsDevCmd_Path!" -arch=!ARCH! -host_arch=!HOST_ARCH! -no_logo -startdir=none || exit !errorlevel!
cd %KEYMAN_ROOT%\core
set BUILDTYPE=%1
@ -81,9 +101,9 @@ if "!COMMAND!" == "configure" (
echo === Configuring Keyman Core for Windows !ARCH! !BUILDTYPE! ===
if exist build\!ARCH!\!BUILDTYPE! rd /s/q build\!ARCH!\!BUILDTYPE!
if "%1" == "--no-tests" (
meson setup build\!ARCH!\!BUILDTYPE! !STATIC_LIBRARY! --buildtype !BUILDTYPE! -Dkeyman_core_tests=false --werror %2 %3 %4 %5 %6 %7 %8 %9 || exit !errorlevel!
meson setup !MESON_CROSS_FILE! build\!ARCH!\!BUILDTYPE! !STATIC_LIBRARY! --buildtype !BUILDTYPE! -Dkeyman_core_tests=false --werror %2 %3 %4 %5 %6 %7 %8 %9 || exit !errorlevel!
) else (
meson setup build\!ARCH!\!BUILDTYPE! !STATIC_LIBRARY! --buildtype !BUILDTYPE! -Dkeyman_core_tests=true --werror %1 %2 %3 %4 %5 %6 %7 %8 %9 || exit !errorlevel!
meson setup !MESON_CROSS_FILE! build\!ARCH!\!BUILDTYPE! !STATIC_LIBRARY! --buildtype !BUILDTYPE! -Dkeyman_core_tests=true --werror %1 %2 %3 %4 %5 %6 %7 %8 %9 || exit !errorlevel!
)
shift
)
@ -103,7 +123,6 @@ if "!COMMAND!" == "test" (
cd ..\..\..
shift
)
goto :eof
rem ----------------------------------

View file

@ -32,6 +32,7 @@ case $BUILDER_OS in
":win Both x86 and x64"
":x86 32-bit Windows (x86) build"
":x64 64-bit Windows (x64) build"
":arm64 64-bit Windows (arm64) build"
)
;;
mac)
@ -96,12 +97,14 @@ builder_describe_internal_dependency \
build:mac build:mac-x86_64 \
build:mac build:mac-arm64 \
build:win build:x86 \
build:win build:x64
build:win build:x64 \
build:win build:arm64 \
builder_describe_outputs \
configure:win /core/build/win/$BUILDER_CONFIGURATION/ \
configure:x86 /core/build/x86/$BUILDER_CONFIGURATION/build.ninja \
configure:x64 /core/build/x64/$BUILDER_CONFIGURATION/build.ninja \
configure:arm64 /core/build/arm64/$BUILDER_CONFIGURATION/build.ninja \
configure:mac /core/build/mac/$BUILDER_CONFIGURATION/ \
configure:mac-x86_64 /core/build/mac-x86_64/$BUILDER_CONFIGURATION/build.ninja \
configure:mac-arm64 /core/build/mac-arm64/$BUILDER_CONFIGURATION/build.ninja \
@ -110,6 +113,7 @@ builder_describe_outputs \
build:win /core/build/win/$BUILDER_CONFIGURATION/BUILT \
build:x86 /core/build/x86/$BUILDER_CONFIGURATION/src/libkeymancore.a \
build:x64 /core/build/x64/$BUILDER_CONFIGURATION/src/libkeymancore.a \
build:arm64 /core/build/arm64/$BUILDER_CONFIGURATION/src/libkeymancore.a \
build:mac /core/build/mac/$BUILDER_CONFIGURATION/libkeymancore.a \
build:mac-x86_64 /core/build/mac-x86_64/$BUILDER_CONFIGURATION/src/libkeymancore.a \
build:mac-arm64 /core/build/mac-arm64/$BUILDER_CONFIGURATION/src/libkeymancore.a \
@ -130,7 +134,7 @@ fi
# Iterate through all possible targets; note that targets that cannot be built
# on the current platform have already been excluded through the archtargets
# settings above
targets=(wasm x86 x64 mac-x86_64 mac-arm64 arch)
targets=(wasm x86 x64 arm64 mac-x86_64 mac-arm64 arch)
do_action() {
local action_function=do_$1
@ -191,6 +195,10 @@ if builder_start_action test:win; then
meson test -C "$MESON_PATH" $testparams
MESON_PATH="$KEYMAN_ROOT/core/build/x64/$BUILDER_CONFIGURATION"
meson test -C "$MESON_PATH" $testparams
# We do not yet have CI/build hardware support for arm64 Windows testing
#MESON_PATH="$KEYMAN_ROOT/core/build/arm64/$BUILDER_CONFIGURATION"
#meson test -C "$MESON_PATH" $testparams
builder_finish_action success test:win
fi

View file

@ -50,7 +50,7 @@ do_configure() {
STANDARD_MESON_ARGS="$STANDARD_MESON_ARGS --cross-file wasm.defs.build --cross-file wasm.build --default-library static"
fi
if [[ $target =~ ^(x86|x64)$ ]]; then
if [[ $target =~ ^(x86|x64|arm64)$ ]]; then
cmd //C build.bat $target $BUILDER_CONFIGURATION configure $BUILD_BAT_keyman_core_tests "${builder_extra_params[@]}"
else
pushd "$THIS_SCRIPT_PATH" > /dev/null
@ -69,7 +69,7 @@ do_configure() {
do_build() {
local target=$1
builder_start_action build:$target || return 0
if [[ $target =~ ^(x86|x64)$ ]]; then
if [[ $target =~ ^(x86|x64|arm64)$ ]]; then
cmd //C build.bat $target $BUILDER_CONFIGURATION build "${builder_extra_params[@]}"
elif $MESON_LOW_VERSION; then
pushd "$MESON_PATH" > /dev/null
@ -88,7 +88,7 @@ do_build() {
do_test() {
local target=$1
builder_start_action test:$target || return 0
if [[ $target =~ ^(x86|x64)$ ]]; then
if [[ $target =~ ^(x86|x64|arm64)$ ]]; then
cmd //C build.bat $target $BUILDER_CONFIGURATION test $testparams
else
if [[ $target == wasm ]] && builder_is_macos; then

13
core/cross-arm64.build Normal file
View file

@ -0,0 +1,13 @@
[host_machine]
system = 'windows'
cpu_family = 'aarch64'
cpu = 'arm64'
endian = 'little'
[binaries]
c = 'cl'
cpp = 'cl'
ar = 'lib'
ld = 'link'
strip = 'llvm-strip' # optional; MSVC doesn’t have a native strip
pkgconfig = 'pkg-config' # optional; used only if you have pkg-config installed

13
core/cross-x64.build Normal file
View file

@ -0,0 +1,13 @@
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[binaries]
c = 'cl'
cpp = 'cl'
ar = 'lib'
ld = 'link'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'

View file

@ -23,7 +23,8 @@ files:
# source: local path of file that gets uploaded to crowdin
# dest: crowdin path in https://crowdin.com/project/keyman
# translation: local path where downloaded translations from crowdin go
# languages_mapping for custom language codes are configured in the Crowdin UI at
# https://crowdin.com/project/keyman/settings#languages
# Android files
# Reference: https://developer.android.com/guide/topics/resources/multilingual-support
@ -34,10 +35,8 @@ files:
languages_mapping:
# Prevent invalid region pap-rPAP. Leaving "in" for Indonesian
android_code:
el-polyton: b+el # TODO: figure out polyton variant
es-419: b+es+419
pap: pap
shu-latn-n: b+shu+latn
- source: /android/KMAPro/kMAPro/src/main/res/values/strings.xml
dest: /android/app/strings.xml
@ -45,10 +44,8 @@ files:
languages_mapping:
# Prevent invalid region pap-rPAP
android_code:
el-polyton: b+el # TODO: figure out polyton variant
es-419: b+es+419
pap: pap
shu-latn-n: b+shu+latn
# Windows files
# Note: we use type: android for the Windows project files
@ -81,7 +78,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /ios/engine/KMEI/KeymanEngine/en.lproj/Localizable.strings
dest: /ios/engine/Localizable.strings
@ -89,7 +85,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /ios/engine/KMEI/KeymanEngine/en.lproj/Localizable.stringsdict
dest: /ios/engine/Localizable.stringsdict
@ -97,7 +92,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /ios/keyman/Keyman/Keyman/en.lproj/Localizable.strings
dest: /ios/app/Localizable.strings
@ -105,7 +99,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
# Linux files
@ -116,7 +109,6 @@ files:
update_option: update_as_unapproved
languages_mapping:
locale_with_underscore:
shu-latn-n: shu@latin
ha: ha
# macOS files
@ -127,7 +119,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/en.lproj/preferences.strings
dest: /mac/app/preferences.strings
@ -135,7 +126,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/en.lproj/KMInfoWindowController.strings
dest: /mac/app/KMInfoWindowController.strings
@ -143,7 +133,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/en.lproj/KMKeyboardHelpWindowController.strings
dest: /mac/app/KMKeyboardHelpWindowController.strings
@ -151,7 +140,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /mac/Keyman4MacIM/Keyman4MacIM/en.lproj/Localizable.strings
dest: /mac/app/Localizable.strings
@ -159,7 +147,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /mac/Keyman4MacIM/Keyman4MacIM/en.lproj/MainMenu.strings
dest: /mac/app/MainMenu.strings
@ -167,7 +154,6 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
# crowdin parameters descriptions:

View file

@ -62,10 +62,10 @@ accent, and one for the vowel.
| `Â, â, ...` | caret (<kbd>^</kbd>), then the vowel key. |
| `Ä, ä, ...` | double-quote (<kbd>"</kbd>), then the vowel key. |
| `Ç, ç` | quote (<kbd>'</kbd>), then lower- or uppercase C. |
| `«, »` | two less-than (<kbd>&lt;&lt;</kbd>) or greater-than (<kbd>&gt;&gt;</kbd>) symbols. |
| `«, »` | two less-than (<kbd>&lt;</kbd><kbd>&lt;</kbd>) or greater-than (<kbd>&gt;</kbd><kbd>&gt;</kbd>) symbols. |
Now that we have decided which character to use and how the user can
enter them, we can start to write the keyboard.
- [Continue with Step 2: Writing the Header](step-2)
- [Back to the Introduction](index)
- [Back to the Introduction](index)

View file

@ -15,7 +15,7 @@ One simple way to create your TSV file is to use the **PrimerPrep**
tool:
1. Install PrimerPrep (info at
<http://lingtransoft.info/apps/primerprep>)
<[https://software.sil.org/primerprep/](https://software.sil.org/primerprep/)>)
2. Run PrimerPrep (note that on the first run it often takes a couple
of minutes; subsequent starts are faster)
3. Click on the Add Text(s) button; select one or more plain text
@ -140,4 +140,4 @@ I’ll save mine as **wordlist.tsv**.
Now that we have our word list, let's compile our model!
[Step 4: Compiling the lexical model](step-4)
[Step 4: Compiling the lexical model](step-4)

View file

@ -5,6 +5,11 @@ import { isProject, loadProject } from './projectLoader.js';
async function runProject(callbacks: CompilerCallbacks, filename: string, callback: (filename:string)=>Promise<boolean>): Promise<boolean> {
const project = await loadProject(filename, callbacks);
if(!project) {
// errors reported by loadProject
return false;
}
for(const file of project.files) {
if(KeymanFileTypes.filenameIs(file.filename, KeymanFileTypes.Source.Project)) {
// Don't accidentally recurse into projects

View file

@ -28,6 +28,9 @@
#include <stdio.h>
#define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
#include <codecvt>
#include "../../../common/windows/cpp/include/legacy_kmx_file.h"
#include "../../../common/windows/cpp/include/legacy_kmx_memory.h"
#include "../../../common/windows/cpp/include/vkeys.h"
@ -366,7 +369,9 @@ PWCHAR ExtString(PWCHAR str)
void wr(FILE *fp, PWSTR buf)
{
fwrite(buf, wcslen(buf) * 2, 1, fp);
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
std::string utf8_string = utf8_conv.to_bytes(buf);
fwrite(utf8_string.c_str(), utf8_string.size(), 1, fp);
}
int SaveKeyboardSource(LPKEYBOARD kbd, LPBYTE lpBitmap, DWORD cbBitmap, char* filename, char* bmpfile)
@ -389,8 +394,6 @@ int SaveKeyboardSource(LPKEYBOARD kbd, LPBYTE lpBitmap, DWORD cbBitmap, char* fi
return 3;
}
fwrite(UTF16Sig, 2, 1, fp);
wsprintfW(buf, L"c Keyboard created by KMDECOMP\n"); wr(fp, buf);
wsprintfW(buf, L"c\n"); wr(fp, buf);
wsprintfW(buf, L"c Meta details: Registered=%d; Version=%x\n", kbd->IsRegistered, kbd->version); wr(fp, buf);

View file

@ -175,7 +175,6 @@ keyboardDropdown.onclick = (value) => {
console.log('setting keyboard to '+value);
keyman.setActiveKeyboard(value, 'en');
ta1.focus();
refreshStatusKeyboard(value);
};
function buildKeyboardList() {
@ -274,17 +273,14 @@ function setupKeyman() {
}
keyboardDropdown.set(keyboardProperties.internalName);
window.sessionStorage.setItem('current-keyboard', keyboardProperties.internalName);
refreshStatusKeyboard();
});
}
function refreshStatusKeyboard(keyboard, model) {
function refreshStatusKeyboard() {
let statusKeyboard = document.getElementById('status-keyboard');
let activeKeyboard = keyman.core.activeKeyboard ? keyman.core.activeKeyboard.id : '';
let keyboards = keyman.getKeyboards();
for(let k of keyboards) {
if(k.InternalName == keyboard) activeKeyboard = k.Name;
}
statusKeyboard.innerText = activeKeyboard;
const debugInfo = keyman.getDebugInfo();
statusKeyboard.innerText = debugInfo.keyboard.id + ' ' + debugInfo.keyboard.version;
}
function refreshStatusModel(model) {
@ -344,7 +340,6 @@ function handleKeyboardsAndModelsResponse(responseText, shouldReload) {
console.log('setting active model to '+lastModel);
keyman.setActiveKeyboard(currentKeyboard, 'en')
selectModel(lastModel);
refreshStatusKeyboard(currentKeyboard);
refreshStatusModel(lastModel);
}, 10);
}

View file

@ -264,7 +264,7 @@
</div>
<div id='addPlatformDialog' title='Add platform'>
<form>
<form id='addPlatformForm'>
<fieldset>
Platform: <select id='selAddPlatform'></select>
</fieldset>
@ -276,7 +276,7 @@
</div>
<div id='addLayerDialog' title='Add layer'>
<form>
<form id='addLayerForm'>
<fieldset>
<label for='addLayerList'>Modifier-based layer:</label> <select id='addLayerList'></select><br />
</fieldset>
@ -292,7 +292,7 @@
</div>
<div id='viewOptionsDialog' title='View options'>
<form>
<form id='viewOptionsForm'>
<fieldset>
<div>By default, only common modifiers are shown in the modifier lists. If
access to more unusual modifier combinations are required, check this option.<br/><br/>
@ -305,7 +305,7 @@
</div>
<div id='platformPropertiesDialog' title='Platform properties'>
<form>
<form id='platformPropertiesForm'>
<fieldset>
<div>Displays the underlying keyboard label on top-left of the key<br/><br/></div>
<input type='checkbox' id='chkDisplayUnderlying'/>
@ -337,7 +337,7 @@
</div>
<div id='layerPropertiesDialog' title='Layer properties'>
<form>
<form id='layerPropertiesForm'>
<fieldset>
Name: <input type='text' id='layerName' size='16' maxlength='64' />
</fieldset>

View file

@ -4,7 +4,7 @@ $(function() {
var layerName = $(this).val();
$('#addLayerList').val(layerName);
if($('#addLayerList')[0].selectedIndex < 0) {
$('#addLayerList').val('(custom)');
$('#addLayerList').val('');
$('#addLayerNote').text('');
} else {
$('#addLayerNote').text(layerName+' is a recognised modifier-aware layer name.');
@ -13,7 +13,7 @@ $(function() {
$('#addLayerList').change(function() {
var v = $(this).val();
if(v == '(custom)') {
if(v == '') {
$('#addLayerName').val('');
$('#addLayerNote').text('');
} else {
@ -45,97 +45,113 @@ $(function() {
// Layer dialogs
//
function submitLayerProperties() {
var newLayerName = $('#layerName').val();
if (!newLayerName.match(/^[a-zA-Z0-9_-]+$/)) {
alert('Layer name must contain only alphanumerics, underscore and hyphen.');
return false;
}
for(var i = 0; i < KVKL[builder.lastPlatform].layer.length; i++) {
if(i != builder.lastLayerIndex && KVKL[builder.lastPlatform].layer[i].id == newLayerName) {
alert('Layer name must not already be in use for the current platform.');
return false;
}
}
builder.saveUndo();
builder.generate();
var platform = KVKL[builder.lastPlatform];
var oldLayerName = platform.layer[builder.lastLayerIndex].id;
let fixup = function(key) {
if (key.layer == oldLayerName) {
key.layer = newLayerName;
}
if (key.nextlayer == oldLayerName) {
key.nextlayer = newLayerName;
}
}
platform.layer.forEach(layer => {
if (layer.row) {
layer.row.forEach(row => {
if (row.key) {
row.key.forEach(key => {
fixup(key);
if (key.sk) {
key.sk.forEach(k => fixup(k));
}
if (key.flick) {
key.flick.forEach(k => fixup(k));
}
if (key.multitap) {
key.multitap.forEach(k => fixup(k));
}
});
}
});
}
});
platform.layer[builder.lastLayerIndex].id = newLayerName;
builder.prepareLayers();
$('#selLayer').val(builder.lastLayerIndex);
builder.selectLayer();
builder.generate();
$('#layerPropertiesDialog').dialog('close');
return false;
}
$('#layerPropertiesForm').on('submit', submitLayerProperties);
$('#layerPropertiesDialog').dialog({
autoOpen: false,
height: 300,
width: 350,
modal: true,
buttons: {
"OK": function () {
var newLayerName = $('#layerName').val();
if (!newLayerName.match(/^[a-zA-Z0-9_-]+$/)) {
alert('Layer name must contain only alphanumerics, underscore and hyphen.');
return;
}
builder.saveUndo();
builder.generate();
var platform = KVKL[builder.lastPlatform];
var oldLayerName = platform.layer[builder.lastLayerIndex].id;
let fixup = function(key) {
if (key.layer == oldLayerName) {
key.layer = newLayerName;
}
if (key.nextlayer == oldLayerName) {
key.nextlayer = newLayerName;
}
}
platform.layer.forEach(layer => {
if (layer.row) {
layer.row.forEach(row => {
if (row.key) {
row.key.forEach(key => {
fixup(key);
if (key.sk) {
key.sk.forEach(k => fixup(k));
}
if (key.flick) {
key.flick.forEach(k => fixup(k));
}
if (key.multitap) {
key.multitap.forEach(k => fixup(k));
}
});
}
});
}
});
platform.layer[builder.lastLayerIndex].id = newLayerName;
builder.prepareLayers();
$('#selLayer').val(builder.lastLayerIndex);
builder.selectLayer();
builder.generate();
$(this).dialog('close');
},
"OK": submitLayerProperties,
"Cancel": function () {
$(this).dialog('close');
}
}
});
function submitLayerDialog() {
var id = $('#addLayerName').val();
if (!id.match(/^[a-zA-Z0-9_-]+$/)) {
alert('Layer name must contain only alphanumerics, underscore and hyphen.');
return false;
}
for(var i = 0; i < KVKL[builder.lastPlatform].layer.length; i++) {
if(KVKL[builder.lastPlatform].layer[i].id == id) {
alert('Layer name must not already be in use for the current platform.');
return false;
}
}
builder.saveUndo();
var layer = $.extend(true, {}, KVKL[builder.lastPlatform].layer[builder.lastLayerIndex]);
layer.id = id;
var n = KVKL[builder.lastPlatform].layer.push(layer) - 1;
builder.selectPlatform();
$('#selLayer').val(n);
builder.selectLayer();
builder.generate(false,true);
$('#addLayerDialog').dialog('close');
return false;
}
$('#addLayerForm').on('submit', submitLayerDialog);
$('#addLayerDialog').dialog({
autoOpen: false,
height: 300,
width: 350,
modal: true,
buttons: {
"OK": function () {
var id = $('#addLayerName').val();
if (!id.match(/^[a-zA-Z0-9_-]+$/)) {
alert('Layer name must contain only alphanumerics, underscore and hyphen.');
return;
}
for(var i = 0; i < KVKL[builder.lastPlatform].layer.length; i++) {
if(KVKL[builder.lastPlatform].layer[i].id == id) {
alert('Layer name must not already be in use for the current platform.');
return;
}
}
builder.saveUndo();
var layer = $.extend(true, {}, KVKL[builder.lastPlatform].layer[builder.lastLayerIndex]);
layer.id = id;
var n = KVKL[builder.lastPlatform].layer.push(layer) - 1;
builder.selectPlatform();
$('#selLayer').val(n);
builder.selectLayer();
builder.generate(false,true);
$(this).dialog('close');
},
"OK": submitLayerDialog,
"Cancel": function () {
$(this).dialog('close');
}

View file

@ -49,26 +49,31 @@ $(function() {
// Platform dialogs
//
function addPlatformSubmit() {
builder.saveUndo();
var platform = $('#selAddPlatform').val();
KVKL[platform] = $.extend(true, {}, KVKL[builder.lastPlatform]); // copy existing platform
builder.preparePlatforms();
$('#selPlatform').val(platform);
builder.selectPlatform();
builder.generate(false,true);
$('#addPlatformDialog').dialog('close');
return false;
}
$('#addPlatformForm').on('submit', addPlatformSubmit);
$('#addPlatformDialog').dialog({
autoOpen: false,
height: 300,
width: 350,
modal: true,
buttons: {
"OK": function () {
builder.saveUndo();
var platform = $('#selAddPlatform').val();
KVKL[platform] = $.extend(true, {}, KVKL[builder.lastPlatform]); // copy existing platform
builder.preparePlatforms();
$('#selPlatform').val(platform);
builder.selectPlatform();
builder.generate(false,true);
$(this).dialog('close');
},
"OK": addPlatformSubmit,
"Cancel": function () {
$(this).dialog('close');
}
@ -117,6 +122,10 @@ $(function() {
builder.restoreSelection(selection);
});
$('#platformPropertiesForm').on('submit', function() {
$('#platformPropertiesDialog').dialog('close');
});
$('#platformPropertiesDialog').dialog({
autoOpen: false,
height: 400,

View file

@ -12,6 +12,11 @@ $(function() {
builder.prepareKey();
});
$('#viewOptionsForm').on('submit', function() {
$('#viewOptionsDialog').dialog('close');
return false;
});
$('#viewOptionsDialog').dialog({
autoOpen: false,
height: 300,

View file

@ -193,7 +193,18 @@ This will create `.mo` files, e.g. `locale/de/LC_MESSAGES/keyman-config.mo`.
### Testing localization
```bash
LANGUAGE=de ./km-config
TEXTDOMAINDIR=./locale LANGUAGE=de ./km-config
```
## Testing that all strings are localizable
To test that all strings can be translated, you can run the following
command. This will create and compile a TEST.po file
which shows all localizable strings in uppercase, and then run
km-config with the TEST.po file.
```bash
make test-po
```
## Debugging unit tests

View file

@ -227,22 +227,22 @@
"menu-settings-spacebar-item-languageKeyboard" = "Idioma e teclado";
/* Label for the "Adjust Keyboard Height" item on the main settings screen */
"menu-settings-adjust-keyboard-height" = "Adjust Keyboard Height";
"menu-settings-adjust-keyboard-height" = "Ajustar altura do teclado";
/* Title for the "Adjust Keyboard Height" settings child screen */
"adjust-keyboard-height-title" = "Adjust Keyboard";
"adjust-keyboard-height-title" = "Ajustar teclado";
/* Label for "Reset to Default Keyboard Height" button on the adjust height screen */
"button-label-reset-default-keyboard-height" = "Reset to Default Keyboard Height";
"button-label-reset-default-keyboard-height" = "Redefinir a Altura Padrão do Teclado";
/* Instruction text to drag keyboard to resize */
"keyboard-drag-instructions" = "Drag arrow control to adjust keyboard height.";
"keyboard-drag-instructions" = "Arraste a seta para ajustar a altura do teclado.";
/* Instruction to rotate to adjust landscape keyboard height (displayed when device is portrait) */
"portrait-keyboard-rotate-instructions" = "Rotate device to adjust for landscape.";
"portrait-keyboard-rotate-instructions" = "Gire o dispositivo para ajustar para paisagem.";
/* Instruction to rotate to adjust portrait keyboard height (displayed when device is landscape) */
"landscape-keyboard-rotate-instructions" = "Rotate device to adjust for portrait.";
"landscape-keyboard-rotate-instructions" = "Girar o dispositivo para ajustar para retrato.";
/* Short text for notification: download failure for keyboard */
"notification-download-failure-keyboard" = "Download do teclado falhou";

1
linux/.gitignore vendored
View file

@ -42,3 +42,4 @@ watch
.pc/
# Debian patch files will be re-generated
debian/patches/
TEST.po

View file

@ -1,3 +1,9 @@
keyman (18.0.245-1) unstable; urgency=medium
* New upstream release.
-- Eberhard Beilharz <eb1@sil.org> Thu, 04 Dec 2025 10:18:49 +0100
keyman (18.0.244-1) unstable; urgency=medium
* New upstream release.

View file

@ -697,13 +697,17 @@ static void
process_persist_action(IBusEngine *engine, km_core_option_item *persist_options) {
g_assert(persist_options != NULL);
g_debug("%s: processing persist options", __FUNCTION__);
IBusKeymanEngine *keyman = (IBusKeymanEngine *)engine;
for (km_core_option_item *option = persist_options; !is_core_options_end(option); option++) {
// Put the keyboard option into DConf
g_assert(option->key != NULL && option->value != NULL);
g_message("%s: Saving keyboard option to DConf", __FUNCTION__);
g_autofree gchar* key = g_utf16_to_utf8((gunichar2*)option->key, -1, NULL, NULL, NULL);
g_autofree gchar* value = g_utf16_to_utf8((gunichar2*)option->value, -1, NULL, NULL, NULL);
g_debug("%s: Saving keyboard option to DConf: %s/%s, %s=%s", __FUNCTION__, keyman->kb_name, keyman->kb_name, key, value);
// Load the current keyboard options from DConf
keyman_put_keyboard_options_todconf(keyman->kb_name, keyman->kb_name, (gchar *)option->key, (gchar *)option->value);
keyman_put_keyboard_options_todconf(keyman->kb_name, keyman->kb_name, key, value);
}
}

View file

@ -447,20 +447,19 @@ keyman_get_keyboard_options_fromdconf(
const gchar *package_id,
const gchar *keyboard_id
) {
g_message(__FUNCTION__);
g_debug("%s: loading keyboard options from DConf for %s/%s", __FUNCTION__, package_id, keyboard_id);
// Obtain keyboard options from DConf
g_autofree gchar *path = g_strdup_printf("%s%s/%s/", KEYMAN_DCONF_OPTIONS_PATH, package_id, keyboard_id);
GSettings *child_settings = g_settings_new_with_path(KEYMAN_DCONF_OPTIONS_CHILD_NAME, path);
gchar **options = NULL;
if (child_settings != NULL)
{
options = g_settings_get_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY);
}
// Obtain keyboard options from DConf
g_autofree gchar* path = g_strdup_printf("%s%s/%s/", KEYMAN_DCONF_OPTIONS_PATH, package_id, keyboard_id);
GSettings* child_settings = g_settings_new_with_path(KEYMAN_DCONF_OPTIONS_CHILD_NAME, path);
gchar** options = NULL;
if (child_settings != NULL) {
options = g_settings_get_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY);
}
g_object_unref(G_OBJECT(child_settings));
g_object_unref(G_OBJECT(child_settings));
return options;
return options;
}
/**
@ -525,7 +524,8 @@ keyman_put_keyboard_options_todconf(
const gchar *option_key,
const gchar *option_value
) {
g_message(__FUNCTION__);
g_message("%s: saving keyboard option to DConf for %s/%s: %s=%s",
__FUNCTION__, package_id, keyboard_id, option_key, option_value);
if (package_id == NULL || keyboard_id == NULL || option_key == NULL || option_value == NULL) {
return;
}
@ -562,7 +562,7 @@ keyman_put_keyboard_options_todconf(
g_autofree gchar *path = g_strdup_printf("%s%s/%s/", KEYMAN_DCONF_OPTIONS_PATH, package_id, keyboard_id);
g_autoptr(GSettings) child_settings = g_settings_new_with_path(KEYMAN_DCONF_OPTIONS_CHILD_NAME, path);
if (child_settings != NULL) {
g_message("writing keyboard options to DConf");
g_debug("%s: writing keyboard options to DConf to %s", __FUNCTION__, path);
g_settings_set_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY, (const gchar *const *)options);
}

View file

@ -300,7 +300,7 @@ function _setup_ibus() {
echo "Starting ibus-daemon..."
#shellcheck disable=SC2086
ibus-daemon ${ARG_VERBOSE-} --daemonize --panel=disable --address=unix:abstract="${TEMP_DATA_DIR}/test-ibus" ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log
ibus-daemon ${ARG_VERBOSE-} --replace --daemonize --panel=disable --address=unix:abstract="${TEMP_DATA_DIR}/test-ibus" ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log
PID=$(pgrep -f "${TEMP_DATA_DIR}/test-ibus")
if [[ "${STANDALONE}" == "--standalone" ]] && [[ "${DOCKER_RUNNING:-false}" != "true" ]] && [[ -z "${TEAMCITY_GIT_PATH:-}" ]]; then
@ -393,9 +393,9 @@ function cleanup() {
# some other ibus processes that belong to the real ibus daemon to
# be killed as well, leaving us with no way to type.
# So we kill the remaining lonely ibus-daemon and start ibus again.
if [[ "$(ibus engine)" == "" ]]; then
echo "# Killing and restarting ibus-daemon"
kill -9 "$(pgrep -u "${USER:-$(whoami)}" ibus-daemon)"
if [[ ! "$(ibus engine &> /dev/null)" ]]; then
echo "# Stopping and starting ibus-daemon"
ibus exit &> /dev/null || kill -9 $(pgrep -u "${USER:-$(whoami)}" ibus-daemon) &> /dev/null || true
ibus start -d
fi
fi

View file

@ -151,13 +151,16 @@ static void test_source(IBusKeymanTestsFixture* fixture, gconstpointer user_data
km::tests::KmxTestSource test_source;
std::string keys = "";
std::u16string expected = u"", expected_context = u"", context = u"";
km::tests::kmx_options options;
km::tests::kmx_options options_from_test;
bool expected_beep = false;
// NOTE: we don't verify expected beeps since engine.c directly calls a gdk method so we
// don't know when it gets called.
g_assert_cmpint(test_source.load_source(sourcefile.c_str(), keys, expected, expected_context, context, options, expected_beep), ==, 0);
g_assert_cmpint(
test_source.load_source(sourcefile.c_str(), keys, expected, expected_context,
context, options_from_test, expected_beep),
==, 0);
for (auto & option : options) {
for (auto& option : options_from_test) {
if (option.type == km::tests::KOT_INPUT) {
auto key = g_utf16_to_utf8((gunichar2 *)option.key.c_str(), option.key.length(), NULL, NULL, NULL);
auto value = g_utf16_to_utf8((gunichar2 *)option.value.c_str(), option.value.length(), NULL, NULL, NULL);
@ -182,6 +185,7 @@ static void test_source(IBusKeymanTestsFixture* fixture, gconstpointer user_data
press_key(fixture, p);
}
// Verify the expected output
if (expected.length() == 0) {
g_assert_null(ibus_im_test_get_text(fixture->ibuscontext));
} else {
@ -189,6 +193,25 @@ static void test_source(IBusKeymanTestsFixture* fixture, gconstpointer user_data
g_assert_cmpstr(ibus_im_test_get_text(fixture->ibuscontext), ==, expectedText);
}
// Verify the expected persisted options
g_settings_sync();
g_auto(GStrv) options = keyman_get_keyboard_options_fromdconf(data->test_name, data->test_name);
for (auto& option : options_from_test) {
// No need to verify KOT_OUTPUT because that's a temporary variable in the keyboard
if (option.type == km::tests::KOT_SAVED) {
g_autofree gchar* expectedKey = g_utf16_to_utf8((gunichar2*)option.key.c_str(), option.key.length(), NULL, NULL, NULL);
g_autofree gchar* expectedValue =
g_utf16_to_utf8((gunichar2*)option.value.c_str(), option.value.length(), NULL, NULL, NULL);
g_autofree gchar* expected = g_strdup_printf("%s=%s", expectedKey, expectedValue);
for (int i = 0; options[i] != NULL; i++) {
if (g_strrstr(options[i], expectedKey) != NULL) {
g_assert_cmpstr(options[i], ==, expected);
break;
}
}
}
}
// Cleanup
g_settings_sync();
}

View file

@ -3,11 +3,8 @@
default:
echo "Use ./build.sh command instead of make!"
version_reconf:
cd .. && ./scripts/reconf.sh
version: version_reconf
$(eval KEYMAN_VERSION := $(shell ./build.sh build && python3 -c "from keyman_config import __releaseversion__; print(__releaseversion__)"))
version:
$(eval KEYMAN_VERSION := $(shell ./build.sh build > /dev/null && python3 -c "from keyman_config import __releaseversion__; print(__releaseversion__)"))
# i18n
@ -31,3 +28,15 @@ $(MOFILES): %/LC_MESSAGES/keyman-config.mo: %.po
msgfmt -v --check --output-file=$@ $^
compile-po: $(MOFILES)
create-test-po:
cd locale && \
msginit --locale=TEST --width=98 --no-translator --input keyman-config.pot --output-file=TEST.po && \
mv TEST.po TEST1.po && \
../../scripts/create-test-po.py TEST1.po TEST.po && \
rm TEST1.po
test-po: create-test-po
mkdir -p locale/TEST/LC_MESSAGES
msgfmt -v --check --output-file=locale/TEST/LC_MESSAGES/keyman-config.mo locale/TEST.po
TEXTDOMAINDIR=./locale LANGUAGE=TEST ./km-config

View file

@ -80,7 +80,7 @@ build_action() {
version.py.in > version.py
popd
pushd buildtools
if [ -f build-langtags.py ]; then
if [[ -f build-langtags.py ]]; then
builder_echo "Create lang_tags_map.py"
python3 ./build-langtags.py
else

View file

@ -161,8 +161,10 @@ def add_standard_arguments(parser):
parser.add_argument('-v', '--verbose', action='store_true', help='verbose logging')
parser.add_argument('-vv', '--veryverbose', action='store_true', help='very verbose logging')
gettext.bindtextdomain('keyman-config', '/usr/share/locale')
if os.environ.get('TEXTDOMAINDIR'):
gettext.bindtextdomain('keyman-config', os.environ['TEXTDOMAINDIR'])
else:
gettext.bindtextdomain('keyman-config', '/usr/share/locale')
gettext.textdomain('keyman-config')

View file

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: keyman\n"
"Report-Msgid-Bugs-To: <support@keyman.com>\n"
"POT-Creation-Date: 2020-08-19 19:17+0200\n"
"PO-Revision-Date: 2022-05-09 04:01\n"
"POT-Creation-Date: 2025-12-18 09:43+0700\n"
"PO-Revision-Date: 2026-01-13 02:35\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@ -17,316 +17,426 @@ msgstr ""
"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 "Non è disponibile né sentry-sdk né corvo. Non è possibile segnalare errori Sentry."
#: keyman_config/downloadkeyboard.py:23
#: keyman_config/downloadkeyboard.py:24
msgid "Download Keyman keyboards"
msgstr "Scarica tastiere Keyman"
#: keyman_config/downloadkeyboard.py:37 keyman_config/keyboard_details.py:49
#: keyman_config/keyboard_details.py:340 keyman_config/view_installed.py:205
#: keyman_config/downloadkeyboard.py:42
msgid "_Back"
msgstr "_Indietro"
#: keyman_config/downloadkeyboard.py:43
msgid "Back to search"
msgstr "Torna alla ricerca"
#: keyman_config/downloadkeyboard.py:48 keyman_config/keyboard_details.py:103
#: keyman_config/keyboard_details.py:186 keyman_config/view_installed.py:174
msgid "_Close"
msgstr "_Chiudi"
#: keyman_config/install_kmp.py:99
#: keyman_config/downloadkeyboard.py:49
msgid "Close dialog"
msgstr "Chiudi dialogo"
#: keyman_config/downloadkeyboard.py:76
msgid "Downloading kmp file failed"
msgstr "Scaricamento file kmp non riuscito"
#: keyman_config/downloadkeyboard.py:79
msgid "Downloading keyboard file failed"
msgstr "Scaricamento del file della tastiera non riuscito"
#: keyman_config/get_kmp.py:34
msgid "System"
msgstr "Sistema"
#: keyman_config/get_kmp.py:36
msgid "Shared"
msgstr "Condiviso"
#: keyman_config/get_kmp.py:38
msgid "User"
msgstr "Utente"
#: keyman_config/get_kmp.py:39
msgid "Unknown"
msgstr "Sconosciuto"
#: keyman_config/install_kmp.py:87
msgid "You do not have permissions to install the keyboard files to the shared area /usr/local/share/keyman"
msgstr "Non hai i permessi per installare i file della tastiera nell'area condivisa /usr/local/share/keyman"
#: keyman_config/install_kmp.py:103
#: keyman_config/install_kmp.py:91
msgid "You do not have permissions to install the documentation to the shared documentation area /usr/local/share/doc/keyman"
msgstr "Non hai i permessi per installare la documentazione nell'area di documentazione condivisa /usr/local/share/doc/keyman"
#: keyman_config/install_kmp.py:107
#: keyman_config/install_kmp.py:95
msgid "You do not have permissions to install the font files to the shared font area /usr/local/share/fonts"
msgstr "Non hai i permessi per installare i file di carattere nell'area di carattere condivisa /usr/local/share/fonts"
#: keyman_config/install_kmp.py:179
#: keyman_config/install_kmp.py:113
#, python-brace-format
msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {package}"
msgstr "install_kmp.py: errore: Nessun kmp.json o kmp.inf trovato in {package}"
msgid "File {kmpfile} doesn't exist"
msgstr "Il file {kmpfile} non esiste"
#: keyman_config/install_kmp.py:246
#: keyman_config/install_kmp.py:132
#, python-brace-format
msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}"
msgstr "install_kmp.py: errore: Nessun kmp.json o kmp.inf trovato in {packageFile}"
msgid "No kmp.json or kmp.inf found in {packageFile}"
msgstr "Nessun kmp.json o kmp.inf trovato in {packageFile}"
#: keyman_config/install_window.py:54
#: keyman_config/install_kmp.py:159
#, python-brace-format
msgid "{packageFile} requires Keyman {keymanVersion} or higher"
msgstr "{packageFile} richiede Keyman {keymanVersion} o superiore"
#: keyman_config/install_kmp.py:307
msgid "Please use fcitx5-configtool to add the keyboard to the desired group"
msgstr "Usare lo strumento di configurazione fcitx5 per aggiungere la tastiera al gruppo desiderato"
#: keyman_config/install_window.py:62
#, python-brace-format
msgid "Installing keyboard/package {keyboardid}"
msgstr "Installazione tastiera/pacchetto {keyboardid}"
#: keyman_config/install_window.py:72 keyman_config/install_window.py:93
msgid "Keyboard is installed already"
msgstr "La tastiera è già installata"
#: 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 "La tastiera {name} è già installata alla versione {version}. Vuoi disinstallare e reinstallarla?"
#: keyman_config/install_window.py:95
msgid "Details"
msgstr "Dettagli"
#: keyman_config/install_window.py:98
msgid "README"
msgstr "README"
#: keyman_config/install_window.py:125
#, python-brace-format
msgid "The file '{kmpfile}' is not a Keyman keyboard package!"
msgstr "Il file '{kmpfile}' non è un pacchetto tastiere Keyman!"
#. i18n: The words in braces (e.g. `{name}`) are placeholders. Don't translate them!
#: keyman_config/install_window.py:141
#, 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 "La tastiera {name} è già installata con una versione più recente {installedversion}. Vuoi disinstallarla e installare la versione precedente {version}?"
#: keyman_config/install_window.py:128
msgid "Keyboard layouts: "
msgstr "Layout della tastiera: "
#: keyman_config/install_window.py:161
msgid "Keyboard is installed already"
msgstr "La tastiera è già installata"
#: keyman_config/install_window.py:147
msgid "Fonts: "
msgstr "Caratteri: "
#: keyman_config/install_window.py:167 keyman_config/keyboard_details.py:96
msgid "Package version: "
msgstr "Versione del pacchetto: "
#: keyman_config/install_window.py:179
msgid "Author: "
msgstr "Autore: "
#: keyman_config/install_window.py:197
msgid "Website: "
msgstr "Sito Web: "
#: keyman_config/install_window.py:211
msgid "Copyright: "
msgstr "copyright: "
#: keyman_config/install_window.py:245
msgid "Details"
msgstr "Dettagli"
#: keyman_config/install_window.py:248
msgid "README"
msgstr "README"
#: keyman_config/install_window.py:256 keyman_config/view_installed.py:200
#: keyman_config/install_window.py:170
msgid "_Install"
msgstr "_Installa"
#: keyman_config/install_window.py:260
#: keyman_config/install_window.py:174
msgid "_Cancel"
msgstr "A_nnulla"
#: keyman_config/install_window.py:305
#: keyman_config/install_window.py:230
msgid "Keyboard layouts: "
msgstr "Layout della tastiera: "
#: keyman_config/install_window.py:250
msgid "Fonts: "
msgstr "Caratteri: "
#: keyman_config/install_window.py:272 keyman_config/keyboard_details.py:81
msgid "Package version: "
msgstr "Versione del pacchetto: "
#: keyman_config/install_window.py:288
msgid "Author: "
msgstr "Autore: "
#: keyman_config/install_window.py:306
msgid "Website: "
msgstr "Sito Web: "
#: keyman_config/install_window.py:321
msgid "Copyright: "
msgstr "copyright: "
#: keyman_config/install_window.py:384
#, python-brace-format
msgid "Keyboard {name} installed"
msgstr "Tastiera {name} installata"
#: keyman_config/install_window.py:310 keyman_config/install_window.py:315
#: keyman_config/install_window.py:397 keyman_config/install_window.py:402
#, python-brace-format
msgid "Keyboard {name} could not be installed."
msgstr "La tastiera {name} non può essere installata."
#: keyman_config/install_window.py:311
#: keyman_config/install_window.py:398
msgid "Error Message:"
msgstr "Messaggio Di Errore:"
#: keyman_config/install_window.py:316
#: keyman_config/install_window.py:403
msgid "Warning Message:"
msgstr "Messaggio Di Attenzione:"
#: keyman_config/keyboard_details.py:37
#: keyman_config/keyboard_details.py:44
#, python-brace-format
msgid "{name} keyboard"
msgstr "{name} tastiera"
#: keyman_config/keyboard_details.py:53
#: keyman_config/keyboard_details.py:77
msgid "Package name: "
msgstr "Nome pacchetto: "
#: keyman_config/keyboard_details.py:79
msgid "Package id: "
msgstr "Id pacchetto: "
#: keyman_config/keyboard_details.py:84
msgid "Package description: "
msgstr "Descrizione del pacchetto: "
#: keyman_config/keyboard_details.py:87
msgid "Package author: "
msgstr "Autore del pacchetto: "
#: keyman_config/keyboard_details.py:90
msgid "Package copyright: "
msgstr "Diritto d'autore del pacchetto: "
#: keyman_config/keyboard_details.py:131
msgid "Keyboard filename: "
msgstr "Nome file tastiera: "
#: keyman_config/keyboard_details.py:139
msgid "Keyboard name: "
msgstr "Nome della tastiera: "
#: keyman_config/keyboard_details.py:140
msgid "Keyboard id: "
msgstr "Keyboard id: "
#: keyman_config/keyboard_details.py:141
msgid "Keyboard version: "
msgstr "Versione tastiera: "
#: keyman_config/keyboard_details.py:143
msgid "Keyboard author: "
msgstr "Autore tastiera: "
#: keyman_config/keyboard_details.py:146
msgid "Keyboard license: "
msgstr "Licenza tastiera: "
#: keyman_config/keyboard_details.py:148
msgid "Keyboard description: "
msgstr "Descrizione tastiera: "
#: keyman_config/keyboard_details.py:191
msgid "ERROR: Keyboard metadata is damaged.\n"
"Please \"Uninstall\" and then \"Install\" the keyboard."
msgstr "ERRORE: I metadati della tastiera sono danneggiati.\n"
"Per favore \"Disinstalla\" e poi \"Installa\" la tastiera."
#: keyman_config/keyboard_details.py:74
msgid "Package name: "
msgstr "Nome pacchetto: "
#: keyman_config/keyboard_details.py:85
msgid "Package id: "
msgstr "Id pacchetto: "
#: keyman_config/keyboard_details.py:108
msgid "Package description: "
msgstr "Descrizione del pacchetto: "
#: keyman_config/keyboard_details.py:121
msgid "Package author: "
msgstr "Autore del pacchetto: "
#: keyman_config/keyboard_details.py:133
msgid "Package copyright: "
msgstr "Diritto d'autore del pacchetto: "
#: keyman_config/keyboard_details.py:174
msgid "Keyboard filename: "
msgstr "Nome file tastiera: "
#: keyman_config/keyboard_details.py:187
msgid "Keyboard name: "
msgstr "Nome della tastiera: "
#: keyman_config/keyboard_details.py:198
msgid "Keyboard id: "
msgstr "Keyboard id: "
#: keyman_config/keyboard_details.py:209
msgid "Keyboard version: "
msgstr "Versione tastiera: "
#: keyman_config/keyboard_details.py:221
msgid "Keyboard author: "
msgstr "Autore tastiera: "
#: keyman_config/keyboard_details.py:232
msgid "Keyboard license: "
msgstr "Licenza tastiera: "
#: keyman_config/keyboard_details.py:243
msgid "Keyboard description: "
msgstr "Descrizione tastiera: "
#: keyman_config/keyboard_details.py:334
#: keyman_config/keyboard_details.py:220
#, python-brace-format
msgid "Scan this code to load this keyboard\n"
"on another device or <a href='{uri}'>share online</a>"
msgstr "Scansiona questo codice per caricare questa tastiera\n"
"su un altro dispositivo o <a href='{uri}'>condividere online</a>"
#: keyman_config/options.py:24
#, python-brace-format
msgid "{packageId} Settings"
msgstr "Impostazioni {packageId}"
#: keyman_config/view_installed.py:30
msgid "Keyman Configuration"
msgstr "Configurazione Keyman"
#: keyman_config/view_installed.py:60
msgid "Choose a kmp file..."
msgstr "Scegli un file kmp..."
#. i18n: file type in file selection dialog
#: keyman_config/view_installed.py:65
msgid "KMP files"
msgstr "File KMP"
#. i18n: column header in table displaying installed keyboards
#: keyman_config/view_installed.py:141
#: keyman_config/keyboard_layouts_widget.py:37
msgid "Icon"
msgstr "Icona"
#. i18n: column header in table displaying installed keyboards
#: keyman_config/view_installed.py:145
#: keyman_config/keyboard_layouts_widget.py:41
msgid "Name"
msgstr "Nome"
#. i18n: column header in table displaying installed keyboards
#: keyman_config/view_installed.py:148
#: keyman_config/keyboard_layouts_widget.py:44
msgid "Version"
msgstr "Versione"
#: keyman_config/view_installed.py:161
#. i18n: column header in table displaying installed keyboards
#: keyman_config/keyboard_layouts_widget.py:47
msgid "Area"
msgstr "Area"
#: keyman_config/keyboard_layouts_widget.py:65
msgid "_Uninstall"
msgstr "_Disinstalla"
#: keyman_config/view_installed.py:162 keyman_config/view_installed.py:304
#: keyman_config/keyboard_layouts_widget.py:66 keyman_config/keyboard_layouts_widget.py:125
msgid "Uninstall keyboard"
msgstr "Disinstalla tastiera"
#: keyman_config/view_installed.py:167
#: keyman_config/keyboard_layouts_widget.py:71
msgid "_About"
msgstr "I_nformazioni"
#: keyman_config/view_installed.py:168 keyman_config/view_installed.py:306
#: keyman_config/keyboard_layouts_widget.py:72 keyman_config/keyboard_layouts_widget.py:127
msgid "About keyboard"
msgstr "Informazioni sulla tastiera"
#: keyman_config/view_installed.py:173
#: keyman_config/keyboard_layouts_widget.py:77
msgid "_Help"
msgstr "A_iuto"
#: keyman_config/view_installed.py:174 keyman_config/view_installed.py:305
#: keyman_config/keyboard_layouts_widget.py:78 keyman_config/keyboard_layouts_widget.py:126
msgid "Help for keyboard"
msgstr "Aiuto per la tastiera"
#: keyman_config/view_installed.py:179
#: keyman_config/keyboard_layouts_widget.py:83
msgid "_Options"
msgstr "_Opzioni"
#: keyman_config/view_installed.py:180 keyman_config/view_installed.py:307
#: keyman_config/keyboard_layouts_widget.py:84 keyman_config/keyboard_layouts_widget.py:128
msgid "Settings for keyboard"
msgstr "Impostazioni per tastiera"
#: keyman_config/view_installed.py:190
msgid "_Refresh"
msgstr "_Aggiorna"
#: keyman_config/view_installed.py:191
msgid "Refresh keyboard list"
msgstr "Aggiorna elenco tastiera"
#: keyman_config/view_installed.py:195
msgid "_Download"
msgstr "_Scarica"
#: keyman_config/view_installed.py:196
msgid "Download and install a keyboard from the Keyman website"
msgstr "Scaricare e installare una tastiera dal sito Keyman"
#: keyman_config/view_installed.py:201
msgid "Install a keyboard from a file"
msgstr "Installa una tastiera da un file"
#: keyman_config/view_installed.py:206
msgid "Close window"
msgstr "Chiudi finestra"
#: keyman_config/view_installed.py:278
#: keyman_config/keyboard_layouts_widget.py:97
#, python-brace-format
msgid "Uninstall keyboard {package}"
msgstr "Disinstalla tastiera {package}"
#: keyman_config/view_installed.py:280
#: keyman_config/keyboard_layouts_widget.py:99
#, python-brace-format
msgid "Help for keyboard {package}"
msgstr "Aiuto per tastiera {package}"
#: keyman_config/view_installed.py:282
#: keyman_config/keyboard_layouts_widget.py:101
#, python-brace-format
msgid "About keyboard {package}"
msgstr "Informazioni sulla tastiera {package}"
#: keyman_config/view_installed.py:284
#: keyman_config/keyboard_layouts_widget.py:103
#, python-brace-format
msgid "Settings for keyboard {package}"
msgstr "Impostazioni per tastiera {package}"
#: keyman_config/view_installed.py:349
#: keyman_config/keyboard_layouts_widget.py:141
msgid "Uninstall keyboard package?"
msgstr "Disinstallare pacchetto tastiera?"
#: keyman_config/view_installed.py:351
#: keyman_config/keyboard_layouts_widget.py:142
#, python-brace-format
msgid "Are you sure that you want to uninstall the {keyboard} keyboard and its fonts?"
msgstr "Sei sicuro di voler disinstallare la tastiera {keyboard} e i suoi caratteri?"
msgid "Are you sure that you want to uninstall the {keyboard} keyboard?"
msgstr "Sei sicuro di voler disinstallare la tastiera {keyboard}?"
#: keyman_config/welcome.py:22
#: keyman_config/keyboard_layouts_widget.py:149
msgid "The following fonts will also be uninstalled:\n"
msgstr "Saranno disinstallati anche i seguenti caratteri:\n"
#: keyman_config/keyboard_layouts_widget.py:160
msgid "Uninstalling keyboard failed.\n\n"
"Error message: "
msgstr "Disinstallazione tastiera non riuscita.\n\n"
"Messaggio di errore: "
#: keyman_config/keyboard_options_view.py:26
#, python-brace-format
msgid "{packageId} Settings"
msgstr "Impostazioni {packageId}"
#: keyman_config/options_widget.py:16
msgid "General"
msgstr "Generale"
#: keyman_config/options_widget.py:24
msgid "Automatically report errors to keyman.com"
msgstr "Segnala automaticamente gli errori su keyman.com"
#: keyman_config/options_widget.py:39
msgid "Simulate AltGr with Ctrl + Alt"
msgstr "Simula AltGr con Ctrl + Alt"
#: keyman_config/sentry_handling.py:55 keyman_config/sentry_handling.py:58
msgid "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
msgstr "Non è disponibile né sentry-sdk né corvo. Non è possibile segnalare errori Sentry."
#: keyman_config/uninstall_kmp.py:85
#, python-format
msgid "You do not have permission to uninstall the files in %s. You need to run this with `sudo`."
msgstr "Non hai i permessi per disinstallare i file in %s. È necessario eseguire con `sudo`."
#: keyman_config/uninstall_kmp.py:136
msgid "Please use fcitx5-configtool to remove the keyboard from the group"
msgstr "Usare lo strumento di configurazione fcitx5 per rimuovere la tastiera dal gruppo"
#: keyman_config/view_installed.py:38
msgid "Keyman Configuration"
msgstr "Configurazione Keyman"
#: keyman_config/view_installed.py:69
msgid "Choose a kmp file..."
msgstr "Scegli un file kmp..."
#. i18n: file type in file selection dialog
#: keyman_config/view_installed.py:74
msgid "KMP files"
msgstr "File KMP"
#: keyman_config/view_installed.py:107
msgid "ibus-daemon is not running. Try to start ibus-daemon now?"
msgstr "ibus-daemon non è in esecuzione. Provare ad avviare ibus-daemon ora?"
#: keyman_config/view_installed.py:109
msgid "If you just recently installed Keyman you might have to reboot or logout and login again."
msgstr "Se hai installato Keyman di recente potrebbe essere necessario riavviare o uscire e accedere di nuovo."
#: keyman_config/view_installed.py:117
msgid "Unable to start ibus-daemon. Please reboot or logout and login again."
msgstr "Impossibile avviare ibus-daemon. Si prega di riavviare o uscire e accedere di nuovo."
#: keyman_config/view_installed.py:151
msgid "Keyboard Layouts"
msgstr "Disposizioni tastiera"
#: keyman_config/view_installed.py:152
msgid "Options"
msgstr "Opzioni"
#: keyman_config/view_installed.py:159
msgid "_Install keyboard..."
msgstr "_Installa tastiera…"
#: keyman_config/view_installed.py:160
msgid "Install a keyboard from a file"
msgstr "Installa una tastiera da un file"
#: keyman_config/view_installed.py:164
msgid "_Download keyboard..."
msgstr "_Scarica tastiera…"
#: keyman_config/view_installed.py:165
msgid "Download and install a keyboard from the Keyman website"
msgstr "Scaricare e installare una tastiera dal sito Keyman"
#: keyman_config/view_installed.py:169
msgid "_Refresh"
msgstr "_Aggiorna"
#: keyman_config/view_installed.py:170
msgid "Refresh keyboard list"
msgstr "Aggiorna elenco tastiera"
#: keyman_config/view_installed.py:175
msgid "Close window"
msgstr "Chiudi finestra"
#: keyman_config/welcome.py:25
#, python-brace-format
msgid "{name} installed"
msgstr "{name} installato"
#: keyman_config/welcome.py:40
#: keyman_config/welcome.py:43
msgid "Open in _Web browser"
msgstr "Apri nel browser _Web"
#: keyman_config/welcome.py:42
#: keyman_config/welcome.py:45
msgid "Open in the default web browser to do things like printing"
msgstr "Apri nel browser web predefinito per fare cose come la stampa"
#: keyman_config/welcome.py:45
#: keyman_config/welcome.py:48
msgid "_OK"
msgstr "_OK"
#: km-config:53
msgid "Missing requirements. Please install python3-fonttools."
msgstr "Requisiti mancanti. Installare python3-fonttools."

View file

@ -6,9 +6,9 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: keyman 14.0\n"
"Project-Id-Version: keyman 19.0\n"
"Report-Msgid-Bugs-To: <support@keyman.com>\n"
"POT-Creation-Date: 2020-08-19 19:17+0200\n"
"POT-Creation-Date: 2025-12-18 09:43+0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,325 +17,434 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: keyman_config/__init__.py:68
msgid "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
msgstr ""
#: keyman_config/downloadkeyboard.py:23
#: keyman_config/downloadkeyboard.py:24
msgid "Download Keyman keyboards"
msgstr ""
#: keyman_config/downloadkeyboard.py:37 keyman_config/keyboard_details.py:49
#: keyman_config/keyboard_details.py:340 keyman_config/view_installed.py:205
#: keyman_config/downloadkeyboard.py:42
msgid "_Back"
msgstr ""
#: keyman_config/downloadkeyboard.py:43
msgid "Back to search"
msgstr ""
#: keyman_config/downloadkeyboard.py:48 keyman_config/keyboard_details.py:103
#: keyman_config/keyboard_details.py:186 keyman_config/view_installed.py:174
msgid "_Close"
msgstr ""
#: keyman_config/install_kmp.py:99
#: keyman_config/downloadkeyboard.py:49
msgid "Close dialog"
msgstr ""
#: keyman_config/downloadkeyboard.py:76
msgid "Downloading kmp file failed"
msgstr ""
#: keyman_config/downloadkeyboard.py:79
msgid "Downloading keyboard file failed"
msgstr ""
#: keyman_config/get_kmp.py:34
msgid "System"
msgstr ""
#: keyman_config/get_kmp.py:36
msgid "Shared"
msgstr ""
#: keyman_config/get_kmp.py:38
msgid "User"
msgstr ""
#: keyman_config/get_kmp.py:39
msgid "Unknown"
msgstr ""
#: keyman_config/install_kmp.py:87
msgid ""
"You do not have permissions to install the keyboard files to the shared area /usr/local/share/"
"keyman"
msgstr ""
#: keyman_config/install_kmp.py:103
#: keyman_config/install_kmp.py:91
msgid ""
"You do not have permissions to install the documentation to the shared documentation area /usr/"
"local/share/doc/keyman"
msgstr ""
#: keyman_config/install_kmp.py:107
#: keyman_config/install_kmp.py:95
msgid ""
"You do not have permissions to install the font files to the shared font area /usr/local/share/"
"fonts"
msgstr ""
#: keyman_config/install_kmp.py:179
#: keyman_config/install_kmp.py:113
#, python-brace-format
msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {package}"
msgid "File {kmpfile} doesn't exist"
msgstr ""
#: keyman_config/install_kmp.py:246
#: keyman_config/install_kmp.py:132
#, python-brace-format
msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}"
msgid "No kmp.json or kmp.inf found in {packageFile}"
msgstr ""
#: keyman_config/install_window.py:54
#: keyman_config/install_kmp.py:159
#, python-brace-format
msgid "{packageFile} requires Keyman {keymanVersion} or higher"
msgstr ""
#: keyman_config/install_kmp.py:307
msgid "Please use fcitx5-configtool to add the keyboard to the desired group"
msgstr ""
#: keyman_config/install_window.py:62
#, python-brace-format
msgid "Installing keyboard/package {keyboardid}"
msgstr ""
#: keyman_config/install_window.py:72 keyman_config/install_window.py:93
msgid "Keyboard is installed already"
msgstr ""
#: 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 ""
#: keyman_config/install_window.py:95
msgid "Details"
msgstr ""
#: keyman_config/install_window.py:98
msgid "README"
msgstr ""
#: keyman_config/install_window.py:125
#, python-brace-format
msgid "The file '{kmpfile}' is not a Keyman keyboard package!"
msgstr ""
#. i18n: The words in braces (e.g. `{name}`) are placeholders. Don't translate them!
#: keyman_config/install_window.py:141
#, 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 ""
#: keyman_config/install_window.py:128
msgid "Keyboard layouts: "
#: keyman_config/install_window.py:161
msgid "Keyboard is installed already"
msgstr ""
#: keyman_config/install_window.py:147
msgid "Fonts: "
msgstr ""
#: keyman_config/install_window.py:167 keyman_config/keyboard_details.py:96
msgid "Package version: "
msgstr ""
#: keyman_config/install_window.py:179
msgid "Author: "
msgstr ""
#: keyman_config/install_window.py:197
msgid "Website: "
msgstr ""
#: keyman_config/install_window.py:211
msgid "Copyright: "
msgstr ""
#: keyman_config/install_window.py:245
msgid "Details"
msgstr ""
#: keyman_config/install_window.py:248
msgid "README"
msgstr ""
#: keyman_config/install_window.py:256 keyman_config/view_installed.py:200
#: keyman_config/install_window.py:170
msgid "_Install"
msgstr ""
#: keyman_config/install_window.py:260
#: keyman_config/install_window.py:174
msgid "_Cancel"
msgstr ""
#: keyman_config/install_window.py:305
#: keyman_config/install_window.py:230
msgid "Keyboard layouts: "
msgstr ""
#: keyman_config/install_window.py:250
msgid "Fonts: "
msgstr ""
#: keyman_config/install_window.py:272 keyman_config/keyboard_details.py:81
msgid "Package version: "
msgstr ""
#: keyman_config/install_window.py:288
msgid "Author: "
msgstr ""
#: keyman_config/install_window.py:306
msgid "Website: "
msgstr ""
#: keyman_config/install_window.py:321
msgid "Copyright: "
msgstr ""
#: keyman_config/install_window.py:384
#, python-brace-format
msgid "Keyboard {name} installed"
msgstr ""
#: keyman_config/install_window.py:310 keyman_config/install_window.py:315
#: keyman_config/install_window.py:397 keyman_config/install_window.py:402
#, python-brace-format
msgid "Keyboard {name} could not be installed."
msgstr ""
#: keyman_config/install_window.py:311
#: keyman_config/install_window.py:398
msgid "Error Message:"
msgstr ""
#: keyman_config/install_window.py:316
#: keyman_config/install_window.py:403
msgid "Warning Message:"
msgstr ""
#: keyman_config/keyboard_details.py:37
#: keyman_config/keyboard_details.py:44
#, python-brace-format
msgid "{name} keyboard"
msgstr ""
#: keyman_config/keyboard_details.py:53
#: keyman_config/keyboard_details.py:77
msgid "Package name: "
msgstr ""
#: keyman_config/keyboard_details.py:79
msgid "Package id: "
msgstr ""
#: keyman_config/keyboard_details.py:84
msgid "Package description: "
msgstr ""
#: keyman_config/keyboard_details.py:87
msgid "Package author: "
msgstr ""
#: keyman_config/keyboard_details.py:90
msgid "Package copyright: "
msgstr ""
#: keyman_config/keyboard_details.py:131
msgid "Keyboard filename: "
msgstr ""
#: keyman_config/keyboard_details.py:139
msgid "Keyboard name: "
msgstr ""
#: keyman_config/keyboard_details.py:140
msgid "Keyboard id: "
msgstr ""
#: keyman_config/keyboard_details.py:141
msgid "Keyboard version: "
msgstr ""
#: keyman_config/keyboard_details.py:143
msgid "Keyboard author: "
msgstr ""
#: keyman_config/keyboard_details.py:146
msgid "Keyboard license: "
msgstr ""
#: keyman_config/keyboard_details.py:148
msgid "Keyboard description: "
msgstr ""
#: keyman_config/keyboard_details.py:191
msgid ""
"ERROR: Keyboard metadata is damaged.\n"
"Please \"Uninstall\" and then \"Install\" the keyboard."
msgstr ""
#: keyman_config/keyboard_details.py:74
msgid "Package name: "
msgstr ""
#: keyman_config/keyboard_details.py:85
msgid "Package id: "
msgstr ""
#: keyman_config/keyboard_details.py:108
msgid "Package description: "
msgstr ""
#: keyman_config/keyboard_details.py:121
msgid "Package author: "
msgstr ""
#: keyman_config/keyboard_details.py:133
msgid "Package copyright: "
msgstr ""
#: keyman_config/keyboard_details.py:174
msgid "Keyboard filename: "
msgstr ""
#: keyman_config/keyboard_details.py:187
msgid "Keyboard name: "
msgstr ""
#: keyman_config/keyboard_details.py:198
msgid "Keyboard id: "
msgstr ""
#: keyman_config/keyboard_details.py:209
msgid "Keyboard version: "
msgstr ""
#: keyman_config/keyboard_details.py:221
msgid "Keyboard author: "
msgstr ""
#: keyman_config/keyboard_details.py:232
msgid "Keyboard license: "
msgstr ""
#: keyman_config/keyboard_details.py:243
msgid "Keyboard description: "
msgstr ""
#: keyman_config/keyboard_details.py:334
#: keyman_config/keyboard_details.py:220
#, python-brace-format
msgid ""
"Scan this code to load this keyboard\n"
"on another device or <a href='{uri}'>share online</a>"
msgstr ""
#: keyman_config/options.py:24
#, python-brace-format
msgid "{packageId} Settings"
msgstr ""
#: keyman_config/view_installed.py:30
msgid "Keyman Configuration"
msgstr ""
#: keyman_config/view_installed.py:60
msgid "Choose a kmp file..."
msgstr ""
#. i18n: file type in file selection dialog
#: keyman_config/view_installed.py:65
msgid "KMP files"
msgstr ""
#. i18n: column header in table displaying installed keyboards
#: keyman_config/view_installed.py:141
#: keyman_config/keyboard_layouts_widget.py:37
msgid "Icon"
msgstr ""
#. i18n: column header in table displaying installed keyboards
#: keyman_config/view_installed.py:145
#: keyman_config/keyboard_layouts_widget.py:41
msgid "Name"
msgstr ""
#. i18n: column header in table displaying installed keyboards
#: keyman_config/view_installed.py:148
#: keyman_config/keyboard_layouts_widget.py:44
msgid "Version"
msgstr ""
#: keyman_config/view_installed.py:161
#. i18n: column header in table displaying installed keyboards
#: keyman_config/keyboard_layouts_widget.py:47
msgid "Area"
msgstr ""
#: keyman_config/keyboard_layouts_widget.py:65
msgid "_Uninstall"
msgstr ""
#: keyman_config/view_installed.py:162 keyman_config/view_installed.py:304
#: keyman_config/keyboard_layouts_widget.py:66 keyman_config/keyboard_layouts_widget.py:125
msgid "Uninstall keyboard"
msgstr ""
#: keyman_config/view_installed.py:167
#: keyman_config/keyboard_layouts_widget.py:71
msgid "_About"
msgstr ""
#: keyman_config/view_installed.py:168 keyman_config/view_installed.py:306
#: keyman_config/keyboard_layouts_widget.py:72 keyman_config/keyboard_layouts_widget.py:127
msgid "About keyboard"
msgstr ""
#: keyman_config/view_installed.py:173
#: keyman_config/keyboard_layouts_widget.py:77
msgid "_Help"
msgstr ""
#: keyman_config/view_installed.py:174 keyman_config/view_installed.py:305
#: keyman_config/keyboard_layouts_widget.py:78 keyman_config/keyboard_layouts_widget.py:126
msgid "Help for keyboard"
msgstr ""
#: keyman_config/view_installed.py:179
#: keyman_config/keyboard_layouts_widget.py:83
msgid "_Options"
msgstr ""
#: keyman_config/view_installed.py:180 keyman_config/view_installed.py:307
#: keyman_config/keyboard_layouts_widget.py:84 keyman_config/keyboard_layouts_widget.py:128
msgid "Settings for keyboard"
msgstr ""
#: keyman_config/view_installed.py:190
msgid "_Refresh"
msgstr ""
#: keyman_config/view_installed.py:191
msgid "Refresh keyboard list"
msgstr ""
#: keyman_config/view_installed.py:195
msgid "_Download"
msgstr ""
#: keyman_config/view_installed.py:196
msgid "Download and install a keyboard from the Keyman website"
msgstr ""
#: keyman_config/view_installed.py:201
msgid "Install a keyboard from a file"
msgstr ""
#: keyman_config/view_installed.py:206
msgid "Close window"
msgstr ""
#: keyman_config/view_installed.py:278
#: keyman_config/keyboard_layouts_widget.py:97
#, python-brace-format
msgid "Uninstall keyboard {package}"
msgstr ""
#: keyman_config/view_installed.py:280
#: keyman_config/keyboard_layouts_widget.py:99
#, python-brace-format
msgid "Help for keyboard {package}"
msgstr ""
#: keyman_config/view_installed.py:282
#: keyman_config/keyboard_layouts_widget.py:101
#, python-brace-format
msgid "About keyboard {package}"
msgstr ""
#: keyman_config/view_installed.py:284
#: keyman_config/keyboard_layouts_widget.py:103
#, python-brace-format
msgid "Settings for keyboard {package}"
msgstr ""
#: keyman_config/view_installed.py:349
#: keyman_config/keyboard_layouts_widget.py:141
msgid "Uninstall keyboard package?"
msgstr ""
#: keyman_config/view_installed.py:351
#: keyman_config/keyboard_layouts_widget.py:142
#, python-brace-format
msgid "Are you sure that you want to uninstall the {keyboard} keyboard and its fonts?"
msgid "Are you sure that you want to uninstall the {keyboard} keyboard?"
msgstr ""
#: keyman_config/welcome.py:22
#: keyman_config/keyboard_layouts_widget.py:149
msgid "The following fonts will also be uninstalled:\n"
msgstr ""
#: keyman_config/keyboard_layouts_widget.py:160
msgid ""
"Uninstalling keyboard failed.\n"
"\n"
"Error message: "
msgstr ""
#: keyman_config/keyboard_options_view.py:26
#, python-brace-format
msgid "{packageId} Settings"
msgstr ""
#: keyman_config/options_widget.py:16
msgid "General"
msgstr ""
#: keyman_config/options_widget.py:24
msgid "Automatically report errors to keyman.com"
msgstr ""
#: keyman_config/options_widget.py:39
msgid "Simulate AltGr with Ctrl + Alt"
msgstr ""
#: keyman_config/sentry_handling.py:55 keyman_config/sentry_handling.py:58
msgid "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting."
msgstr ""
#: keyman_config/uninstall_kmp.py:85
#, python-format
msgid "You do not have permission to uninstall the files in %s. You need to run this with `sudo`."
msgstr ""
#: keyman_config/uninstall_kmp.py:136
msgid "Please use fcitx5-configtool to remove the keyboard from the group"
msgstr ""
#: keyman_config/view_installed.py:38
msgid "Keyman Configuration"
msgstr ""
#: keyman_config/view_installed.py:69
msgid "Choose a kmp file..."
msgstr ""
#. i18n: file type in file selection dialog
#: keyman_config/view_installed.py:74
msgid "KMP files"
msgstr ""
#: keyman_config/view_installed.py:107
msgid "ibus-daemon is not running. Try to start ibus-daemon now?"
msgstr ""
#: keyman_config/view_installed.py:109
msgid "If you just recently installed Keyman you might have to reboot or logout and login again."
msgstr ""
#: keyman_config/view_installed.py:117
msgid "Unable to start ibus-daemon. Please reboot or logout and login again."
msgstr ""
#: keyman_config/view_installed.py:151
msgid "Keyboard Layouts"
msgstr ""
#: keyman_config/view_installed.py:152
msgid "Options"
msgstr ""
#: keyman_config/view_installed.py:159
msgid "_Install keyboard..."
msgstr ""
#: keyman_config/view_installed.py:160
msgid "Install a keyboard from a file"
msgstr ""
#: keyman_config/view_installed.py:164
msgid "_Download keyboard..."
msgstr ""
#: keyman_config/view_installed.py:165
msgid "Download and install a keyboard from the Keyman website"
msgstr ""
#: keyman_config/view_installed.py:169
msgid "_Refresh"
msgstr ""
#: keyman_config/view_installed.py:170
msgid "Refresh keyboard list"
msgstr ""
#: keyman_config/view_installed.py:175
msgid "Close window"
msgstr ""
#: keyman_config/welcome.py:25
#, python-brace-format
msgid "{name} installed"
msgstr ""
#: keyman_config/welcome.py:40
#: keyman_config/welcome.py:43
msgid "Open in _Web browser"
msgstr ""
#: keyman_config/welcome.py:42
#: keyman_config/welcome.py:45
msgid "Open in the default web browser to do things like printing"
msgstr ""
#: keyman_config/welcome.py:45
#: keyman_config/welcome.py:48
msgid "_OK"
msgstr ""
#: km-config:53
msgid "Missing requirements. Please install python3-fonttools."
msgstr ""

43
linux/scripts/create-test-po.py Executable file
View file

@ -0,0 +1,43 @@
#!/usr/bin/python3
# This script is used to convert all strings in a .po file to uppercase.
# It is used to test the .po file translations.
import polib
import sys
import re
# Requires installation of python3-polib
def uppercase_except_braces(s):
# Replace all text outside braces and %... (to next space) with uppercase, keep inside braces and %... as is
def repl(match):
text = match.group(0)
if text.startswith('{') and text.endswith('}'):
return text
return text if text.startswith('%') else text.upper()
# This regex splits the string into:
# - brace blocks: { ... }
# - percent blocks: %... (up to next space or end of string)
# - everything else
pattern = r'\{[^}]*\}|%[^\s]*|[^{%]+'
return re.sub(pattern, repl, s)
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <file.po> <outfile.po>")
sys.exit(1)
po = polib.pofile(sys.argv[1])
for entry in po:
# Only update if not a fuzzy translation and not the header
if not entry.obsolete and entry.msgid and not entry.msgid_plural:
entry.msgstr = uppercase_except_braces(entry.msgid)
elif not entry.obsolete and entry.msgid:
# For plural forms
for idx in entry.msgstr_plural:
entry.msgstr_plural[idx] = uppercase_except_braces(entry.msgid_plural)
po.save(f"{sys.argv[2]}")
print(f"Updated file written to {sys.argv[2]}")

View file

@ -33,7 +33,7 @@ else
fi
echo "ppa: ${ppa}"
distributions="${DIST:-jammy noble plucky questing resolute}"
distributions="${DIST:-jammy noble questing resolute}"
packageversion="${PACKAGEVERSION:-1~sil1}"
BASEDIR=$(pwd)

View file

@ -31,6 +31,9 @@
/* Message displayed in Configuration window when keyboard metadata cannot be loaded */
"message-error-unknown-metadata" = "sconosciuto";
/* Configuration window section heading when keyboard has no package name */
"unknown-package-name" = "Pacchetto tastiera senza nome";
/* Button text to acknowledge that .kmp file could not be read */
"button-keyboard-file-unreadable" = "OK";

View file

@ -67,8 +67,11 @@
/* copyright label in the Package Information window */
"copyright-label" = "Direitos de autor:";
/* message displayed to alert user to need grant accessibility permission */
/* message displayed to alert user to grant accessibility permission in Preferences, pre-Ventura */
"privacy-alert-text" = "Para funcionar corretamente, o Keyman requer recursos de acessibilidade:\n\nConceda acesso em Definições do Sistema, Segurança e Privacidade.\nReinício do sistema.";
/* message displayed to alert user to grant accessibility permission in Settings, for macOS Ventura and later */
"privacy-alert-text-ventura" = "Para funcionar corretamente, o Keyman requer recursos de acessibilidade:\n\nConceda acesso em Definições do Sistema, Segurança e Privacidade.\nReinicie o seu sistema.";
/* Text of menu item in Input Menu when no Keyboards are configured -- include parentheses */
"no-keyboard-configured-menu-placeholder" = "(Nenhum teclado configurado)";

View file

@ -200,7 +200,7 @@ while (( DETACH_SUCCESS < 10 )); do
echo "hdiutil detach reported failure code ${DETACH_RESULT}"
fi
if [[ $DETACH_RESULT != 0 ]] || [[ -d "$STAGING_DIR" ]] ; then
(( DETACH_SUCCESS++ ))
(( DETACH_SUCCESS++ )) || true
echo "Failed to unmount: \"$STAGING_DIR\" on attempt #$DETACH_SUCCESS. Waiting 5 seconds to try again."
if (( DETACH_SUCCESS == 6 )); then
echo " Note: Detach failed first five times, so now attempting with '-force'"

View file

@ -470,10 +470,9 @@ CFStringRef createStringForKey(CGKeyCode keyCode)
CGKeyCode keyCodeForChar(const char c)
{
static CFMutableDictionaryRef charToCodeDict = NULL;
CGKeyCode code;
UniChar character = c;
CFStringRef charStr = NULL;
/* Generate table of keycodes and characters. */
if (charToCodeDict == NULL) {
size_t i;
@ -482,7 +481,7 @@ CGKeyCode keyCodeForChar(const char c)
&kCFCopyStringDictionaryKeyCallBacks,
NULL);
if (charToCodeDict == NULL) return UINT16_MAX;
/* Loop through every keycode (0 - 127) to find its current mapping. */
for (i = 0; i < 128; ++i) {
CFStringRef string = createStringForKey((CGKeyCode)i);
@ -492,15 +491,21 @@ CGKeyCode keyCodeForChar(const char c)
}
}
}
charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);
/* Our values may be NULL (0), so we need to use this function. */
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr,
(const void **)&code)) {
/* Our values may be NULL (0), so we need to use this function.
* Use a pointer-sized variable to receive the value, since CFDictionary
* stores values as void pointers (64-bit on modern systems), then cast
* to CGKeyCode (uint16_t). */
const void *value = NULL;
CGKeyCode code;
if (CFDictionaryGetValueIfPresent(charToCodeDict, charStr, &value)) {
code = (CGKeyCode)(uintptr_t)value;
} else {
code = UINT16_MAX;
}
CFRelease(charStr);
return code;
}

View file

@ -74,7 +74,7 @@ function do_publish() {
-sice:ICE82 -sice:ICE80 \
-dWixUILicenseRtf=License.rtf \
-out firstvoices.msi \
-ext WixUIExtension firstvoices.wixobj desktopui.wixobj
-ext WixUIExtension -ext WixUtilExtension firstvoices.wixobj desktopui.wixobj
#
# Sign the installation archive

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product UpgradeCode="f212edf7-0bef-43bb-8fc2-2625ae7bbfca" Manufacturer="SIL International"
Id="*" Name="$(var.PRODUCTNAME) $(var.RELEASE)" Version="$(var.KEYMAN_VERSION)" Language="1033">
<Package Keywords="Keyman,$(var.PRODUCTNAME),Keyboard,Engine"
@ -37,6 +37,11 @@
<Property Id='OnlineProductID' Value='30' />
<!-- CE38CB16_4448_4432_851B_B3FCE3AF464F is the GUID for the keyman engine merge
module package; this makes the WIX_NATIVE_MACHINE property available to it -->
<SetProperty Id="WIX_NATIVE_MACHINE.CE38CB16_4448_4432_851B_B3FCE3AF464F" Value="[WIX_NATIVE_MACHINE]" Before="LaunchConditions"/>
<Directory Id="TARGETDIR" Name="SourceDir" DiskId="1">
<Merge Id="keymanengine" Language='1033' SourceFile='$(var.ROOT)\src\engine\inst\keymanengine.msm' />
@ -179,6 +184,7 @@
<Property Id="ALLUSERS">1</Property>
<UIRef Id="WixUI_FeatureTree"/>
<PropertyRef Id="WIX_NATIVE_MACHINE" />
<Icon Id="appicon.ico" SourceFile="..\branding\appicon.ico" />
<Icon Id="KMSHELL.ico" SourceFile="..\branding\cfgicon.ico" />

View file

@ -6,7 +6,7 @@ set -e
set -u
if [[ $# -lt 1 ]]; then
echo "This script is called by shellHelperFunctions.sh, _select_node_version_with_nvm()"
echo "This script is called by node.inc.sh, _node_select_version_with_nvm()"
echo "during build.sh configure steps. It is not intended to be called directly, as it"
echo "is a wrapper for nvm."
exit 99
@ -25,7 +25,7 @@ fi
# them also! Safest way to work around this is to load nvm in a child process
# and run it there. Downside is then of course we don't get the `PATH` changes
# that nvm does for us, so we have to do it ourselves back in the caller,
# `_select_node_version_with_nvm()`.
# `_node_select_version_with_nvm()`.
#
# Note: the readonly attribute for variables is not inherited by child
# processes.
@ -46,7 +46,7 @@ if ! nvm use "${REQUIRED_NODE_VERSION}"; then
nvm use "${REQUIRED_NODE_VERSION}"
fi
# Beware the hardcoded path below -- it should already be in the system PATH
# Beware the hardcoded path below -- node.inc.sh will add it to PATH if necessary
mkdir -p "$HOME/.keyman"
rm -f "$HOME/.keyman/node"

View file

@ -4,7 +4,7 @@ export const testBuildConfigurations = {
'ios': ['Keyman_iOS_TestPullRequests', 'Keyman_iOS_TestSamplesAndTestProjects'],
'linux': ['KeymanLinux_TestPullRequests', 'Keyman_Linux_Test_Integration', 'Keyman_Common_KPAPI_TestPullRequests_Linux', 'deb-pr-packaging_GitHub'],
'mac': ['Keyman_KeymanMac_PullRequests', 'Keyman_Common_KPAPI_TestPullRequests_macOS'],
'windows': ['KeymanDesktop_TestPullRequests', 'KeymanDesktop_TestPrRenderOnScreenKeyboards', 'Keyman_Common_KPAPI_TestPullRequests_Windows'],
'windows': ['KeymanDesktop_TestPullRequests', 'KeymanDesktop_TestPrRenderOnScreenKeyboards', 'Keyman_Common_KPAPI_TestPullRequests_Windows', 'core-arm64-windows-test_GitHub'],
'web': ['Keymanweb_TestPullRequests', 'Keyman_Common_KPAPI_TestPullRequests_WASM'],
'developer': ['Keyman_Developer_Test', 'npm-publish_GitHub'],

View file

@ -87,7 +87,7 @@ bc_test_android=(KeymanAndroid_TestPullRequests KeymanAndroid_TestSamplesAndTest
bc_test_ios=(Keyman_iOS_TestPullRequests Keyman_iOS_TestSamplesAndTestProjects)
bc_test_linux=(KeymanLinux_TestPullRequests Keyman_Linux_Test_Integration Keyman_Common_KPAPI_TestPullRequests_Linux deb-pr-packaging_GitHub)
bc_test_mac=(Keyman_KeymanMac_PullRequests Keyman_Common_KPAPI_TestPullRequests_macOS)
bc_test_windows=(KeymanDesktop_TestPullRequests KeymanDesktop_TestPrRenderOnScreenKeyboards Keyman_Common_KPAPI_TestPullRequests_Windows)
bc_test_windows=(KeymanDesktop_TestPullRequests KeymanDesktop_TestPrRenderOnScreenKeyboards Keyman_Common_KPAPI_TestPullRequests_Windows core-arm64-windows-test_GitHub)
bc_test_web=(Keymanweb_TestPullRequests Keyman_Common_KPAPI_TestPullRequests_WASM)
bc_test_developer=(Keyman_Developer_Test Keyman_Test_Developer_Mac Keyman_Test_Developer_Linux npm-publish_GitHub)

View file

@ -4,19 +4,19 @@ Localization for Keyman is maintained at https://translate.keyman.com
Downloading and updating files between Keyman and Crowdin happens
on GitHub by way of the Crowdin git integration. The configuration file for all platforms
is a YAML file named `/crowdin.yml`. Currently, the git integration tracks the `master` branch.
is a YAML file named [crowdin.yml](../../../crowdin.yml). Currently, the git integration tracks the `master` branch.
A GitHub action runs every two weeks to update the source files in Crowdin, which are organized in a top-level folder "master".
A daily GitHub action to update the source files in Crowdin, which are organized in a top-level folder "master".
For most of our platforms, the only thing that needs to be done manually is to update `crowdin.yml` if new files get added
For most of our platforms, the only thing that needs to be done manually is to update `crowdin.yml` if new source files get added
(and of course translating the strings on the [Crowdin website](https://crowdin.com/project/keyman)).
## Manual upload and download with Crowdin CLI
The following describes how alternatively the Crowdin CLI (v3) tool could be used to
The following describes how alternatively the Crowdin CLI (v4) tool could be used to
automate downloading and updating files between Keyman and Crowdin.
On Windows, use `crowdin.bat` instead of `crowdin` for all the syntax below.
**Note**: On Windows, use `crowdin.bat` instead of `crowdin` for all the syntax below.
### Add File
@ -33,8 +33,8 @@ For example, `android/KMEA/strings.xml` string uses
### Setup
Install the [Crowdin CLI (v3)](https://support.crowdin.com/cli-tool-v3/) for your OS.
Note, it has a prerequisite on Java 8.
Install [Crowdin CLI v4](https://crowdin.github.io/crowdin-cli/installation) for your OS.
Note, it has a prerequisite on Java 17 LTS.
#### Environment Variables
@ -55,6 +55,21 @@ crowdin list project
You should see the CLI fetching project info and generating a list of files associated with the
project.
### Configuring Custom Language Codes
https://crowdin.com/project/keyman/settings#languages
Only the project owner (sil_ltops) can edit custom language codes (at the bottom of the "Target Languages" list).
For some of these, the language mapping needs to be maintained in the "Language Mapping" button on the project settings menu (instead of the [crowdin.yml](../../../crowdin.yml)) configuration file.
Language mappings have been set up for "Greek (Polytonic)" and "Shuwa (Latin)" so downloading with the Crowdin CLI would be:
```
crowdin download -b master -l el-polyton
crowdin download -b master -l shu-latn-n
```
### Downloading from Crowdin
Since Crowdin is tracking the `master` branch, download translations will be zipped into a `master` folder.

View file

@ -69,6 +69,10 @@ _node_select_version_with_nvm() {
else
# launch nvm in a sub process, see _builder_nvm.sh for details
"${KEYMAN_ROOT}/resources/build/_builder_nvm.sh" "${REQUIRED_NODE_VERSION}"
if ! echo "${PATH}" | grep -qF "${HOME}/.keyman/node"; then
export PATH="${HOME}/.keyman/node:${PATH}"
fi
fi
# Now, check that the node version is correct, on all systems

View file

@ -54,6 +54,8 @@
summary += addStatus(o, 'build', status.context, status.state);
} else if(status.context == 'npm pack/publish') {
summary += addStatus(o, 'build', status.context, status.state);
} else if(status.context == 'Keyman Core - ARM64 test') {
summary += addStatus(o, 'build', status.context, status.state);
} else if(status.context == 'check/web/file-size') {
// Ignore check/web/file-size -- we won't block automerge for this at this point
summary += addLog(`Skipping ${status.context}`);
@ -81,9 +83,10 @@
const { state, type } = filtered_statuses[context];
if(type == 'unknown') {
// We special-case for unknown status checks, and never permit them
console.error(`An unknown context ${context} was found, cannot calculate build status.`);
// Note: function reduceStatuses() is where new status checks can be added
console.error(`An unknown context "${context}" was found, cannot calculate build status.`);
return [
'error', `An unknown context ${context} was found, cannot calculate build status.`, summary
'error', `An unknown context "${context}" was found, cannot calculate build status.`, summary
];
}
if(type == 'build') {

View file

@ -6,4 +6,14 @@ history has been found, increments the version, and creates a PR for the
increment.
It is wrappered by ../../teamcity/triggers/trigger-release-builds.sh for normal CI
usage.
usage.
## Reporting on pending changes to stable
This script will give you a report on the pending changes to the most recent
Keyman stable release, based on recently merged pull requests on the stable-x.y
branch:
```bash
./build.sh report-stable-changes
```

View file

@ -10,13 +10,29 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
################################ Main script ################################
builder_describe "Build version tooling" clean configure build
# assuming that last stable release is also minor version .0 at this point
STABLE_VERSION_MINOR=0
STABLE_VERSION_MAJOR=$(( $KEYMAN_VERSION_MAJOR - 1 ))
builder_describe "Build version tooling" clean configure build \
"report-stable-changes Report on pending changes to most recent Keyman stable-$STABLE_VERSION_MAJOR.$STABLE_VERSION_MINOR release"
builder_describe_outputs \
configure /resources/build/version/node_modules \
build /resources/build/version/build/src/index.js
builder_describe_internal_dependency \
report-stable-changes:project build:project
builder_parse "$@"
function do_report_stable_changes() {
cd "$KEYMAN_ROOT"
git fetch
node resources/build/version report-history -b "stable-$STABLE_VERSION_MAJOR.$STABLE_VERSION_MINOR" -t "$GITHUB_TOKEN" --github-pr
}
builder_run_action clean rm -rf build/ node_modules/ dist/ lib/
builder_run_action configure node_select_version_and_npm_ci
builder_run_action build tsc --build
builder_run_action report-stable-changes do_report_stable_changes

View file

@ -18,6 +18,8 @@ DELPHI_MSBUILD_FLAG_DEBUG="//p:Config=$TARGET_PATH"
# Visual C++ x86, x64; Delphi x86
WIN32_TARGET_PATH=bin/Win32/$TARGET_PATH
X64_TARGET_PATH=bin/x64/$TARGET_PATH
ARM64_TARGET_PATH=bin/arm64/$TARGET_PATH
ARM64EC_TARGET_PATH=bin/ARM64EC/$TARGET_PATH
# Delphi x86, x64
# WIN32_TARGET_PATH=...

View file

@ -98,7 +98,7 @@ echo "trigger-release-builds.sh: building resources/build/version"
pushd "$KEYMAN_ROOT"
npm ci
builder_launch /resources/build/version/build.sh
"$KEYMAN_ROOT/resources/build/version/build.sh"
echo "trigger-release-builds.sh: running resources/build/version"
pushd "$KEYMAN_ROOT"

View file

@ -56,3 +56,5 @@ keyman.addKeyboards('french','sil_euro_latin@sv','sil_euro_latin@no')
```
This will install three keyboards - one for French (named, quite simply, "French") and two copies of the EuroLatin keyboard - one for Swedish and one for Norwegian.
[Previous: What is a Keyboard?](what-is-a-keyboard) | [Next: Additional Examples](examples/)

View file

@ -40,8 +40,8 @@ Also include the following HTML code:
```html
<head>
<!-- Load the KeymanWeb engine -->
<script src="https://s.keyman.com/kmw/engine/17.0.330/keymanweb.js" type="text/javascript"></script>
<script src="https://s.keyman.com/kmw/engine/17.0.330/kmwuitoggle.js" type="text/javascript"></script>
<script src="js/keymanweb.js" type="text/javascript"></script>
<script src="js/kmwuitoggle.js" type="text/javascript"></script>
<!-- // Also be sure to load your keyboards. Note that stubs will not work with this
// example without detailing paths precisely in the init() call's parameter.-->
</head>

View file

@ -19,8 +19,8 @@ The source code for the page may be seen below.
<meta charset="UTF-8">
<title>KeymanWeb - A First Example</title>
<script src='https://s.keyman.com/kmw/engine/17.0.330/keymanweb.js'></script>
<script src='https://s.keyman.com/kmw/engine/17.0.330/kmwuitoggle.js'></script>
<script src='https://s.keyman.com/kmw/engine/18.0.245/keymanweb.js'></script>
<script src='https://s.keyman.com/kmw/engine/18.0.245/kmwuitoggle.js'></script>
<script>
(function() {
keyman.init({attachType:'auto'}).then(function() {
@ -38,16 +38,28 @@ The source code for the page may be seen below.
## The Breakdown
- The `<script>` inclusion `<script src='https://s.keyman.com/kmw/engine/17.0.330/keymanweb.js'></script>` loads the Keyman Engine for Web script for the page.
- The `<script>` inclusion `<script
src='https://s.keyman.com/kmw/engine/18.0.245/keymanweb.js'></script>` loads the Keyman Engine
for Web script for the page.
- `(function() { keyman.init(); });` serves to initialize the web engine with default settings. By adding the object `{attachType:'auto'}` as a parameter to our `keyman.init()` call, the KeymanWeb engine will then link into any detected input elements automatically, regardless of browser or device, as part of its initialization.
- `(function() { ... keyman.init( ... ); ... })(keyman);` serves to initialize the web engine with default settings.
By adding the object `{attachType:'auto'}` as a parameter to our `keyman.init()` call, the
KeymanWeb engine will then link into any detected input elements automatically, regardless of
browser or device, as part of its initialization.
- The other `<script>` inclusion, `<script src='https://s.keyman.com/kmw/engine/17.0.330/kmwuitoggle.js'></script>`, creates the language menu seen on non-mobile devices and the on-screen keyboard toggle button. For other options, see our [User Interface Design](user-interface-design) page.
- The other `<script>` inclusion, `<script
src='https://s.keyman.com/kmw/engine/18.0.245/kmwuitoggle.js'></script>`, creates the language
menu seen on non-mobile devices and the on-screen keyboard toggle button. For other options,
see our [User Interface Design](user-interface-design) page.
- The calls to `keyman.addKeyboards()` in the source above link in the two example Keyman keyboards used in this demo from our CDN server. For more info on how to include keyboards in your KeymanWeb installation, check the [Adding Keyboards](adding-keyboards) page.
- The calls to `keyman.addKeyboards()` in the source above link in the two example Keyman
keyboards used in this demo from our CDN server. For more info on how to include keyboards in
your KeymanWeb installation, check the [Adding Keyboards](adding-keyboards) page.
## API References
- On initialization: [`keyman.init()`](../reference/core/init).
- On including keyboards: [`keyman.addKeyboards()`](../reference/core/addKeyboards).
[Next: User Interface Design](user-interface-design)

Some files were not shown because too many files have changed in this diff Show more