diff --git a/HISTORY.md b/HISTORY.md index eef0916c27..5d3b0ccca1 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,41 @@ # Keyman Version History +## 14.0.226 beta 2021-01-20 + +* fix(windows, common/core/desktop): context mismatch with if and dk (#4276) +* chore(common): Check in crowdin files for de (German) (#4295) +* feat(android/app): Add option to change display language (#4261) +* fix(developer/compilers): fixes developer build breakage from #4291 (#4299) +* fix(android/app): Handle keyman protocol from external browser (#4292) + +## 14.0.225 beta 2021-01-19 + +* fix(android/samples): Fix Sentry dependencies (#4267) +* fix(web): better font-wait null guards (#4286) +* fix(web): uses CSS line-height to vertically center oversized OSK keycaps (#4255) +* fix(developer): disable TSentryClient on WINE (#4274) +* fix(web): no key previews for special keys reliant on keyboard-specific OSK font (#4282) +* fix(web): default kbd ui name is now generic (#4293) +* fix(developer/compilers): fixes dependency versioning on alpha, beta tiers (#4291) + +## 14.0.224 beta 2021-01-18 + +* fix(android): Popup misalignments and compatibility with WeChat, Telegram (#4254) +* chore(web): sample pages now wait on init's promise for keyboard loading (#4253) + +## 14.0.223 beta 2021-01-15 + +* fix(windows): typo in font helper string (#4251) +* chore(android/app): Add Obolo language from crowdin (#4256) +* fix(web): unexpected errors in OSK / banner position calculations (#4238) +* chore(linux): Improve version number for debian package (#4258) + +## 14.0.222 beta 2021-01-14 + +* chore(common): Check in crowdin files for km (Khmer) (#4228) +* fix(web): OSK key preview positioning (#4241) +* fix(web): disables predictive text on Opera mini (#4243) + ## 14.0.221 beta 2021-01-13 * fix(windows): fix menu popup position (#4175) diff --git a/VERSION.md b/VERSION.md index f14f5c27ae..5719a590d6 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -14.0.222 \ No newline at end of file +14.0.227 \ No newline at end of file diff --git a/android/KMAPro/kMAPro/src/main/AndroidManifest.xml b/android/KMAPro/kMAPro/src/main/AndroidManifest.xml index 73b1ae679b..ca79447d3a 100644 --- a/android/KMAPro/kMAPro/src/main/AndroidManifest.xml +++ b/android/KMAPro/kMAPro/src/main/AndroidManifest.xml @@ -261,6 +261,12 @@ android:parentActivityName=".KeymanSettingsActivity" android:launchMode="singleTask" android:theme="@style/AppTheme.Base" /> + > list = null; diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/GetStartedActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/GetStartedActivity.java index ede2962217..d159e1a197 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/GetStartedActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/GetStartedActivity.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import com.tavultesoft.kmea.BaseActivity; import com.tavultesoft.kmea.KMManager; import com.tavultesoft.kmea.data.Keyboard; @@ -29,7 +30,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.widget.TextView; -public class GetStartedActivity extends AppCompatActivity { +public class GetStartedActivity extends BaseActivity { private static ListView listView = null; private static ArrayList> list = null; diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/InfoActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/InfoActivity.java index 01bb79d4f5..7802f239ca 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/InfoActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/InfoActivity.java @@ -4,6 +4,7 @@ package com.tavultesoft.kmapro; +import com.tavultesoft.kmea.BaseActivity; import com.tavultesoft.kmea.BuildConfig; import com.tavultesoft.kmea.KMManager; import com.tavultesoft.kmea.KMManager.FormFactor; @@ -20,7 +21,7 @@ import android.widget.TextView; import android.annotation.SuppressLint; import androidx.appcompat.app.AppCompatActivity; -public class InfoActivity extends AppCompatActivity { +public class InfoActivity extends BaseActivity { private final static String TAG = "InfoActivity"; private WebView webView; private final String HELP_PRODUCTION_HOST = "help.keyman.com"; diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KMPBrowserActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KMPBrowserActivity.java index 6e3ef52681..f25af7371a 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KMPBrowserActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KMPBrowserActivity.java @@ -19,6 +19,7 @@ import android.webkit.WebView; import android.webkit.WebViewClient; import androidx.appcompat.app.AppCompatActivity; +import com.tavultesoft.kmea.BaseActivity; import com.tavultesoft.kmea.KMManager; import com.tavultesoft.kmea.util.KMPLink; @@ -27,7 +28,7 @@ import java.util.regex.Pattern; import static android.app.Application.getProcessName; -public class KMPBrowserActivity extends AppCompatActivity { +public class KMPBrowserActivity extends BaseActivity { private static final String TAG = "KMPBrowserActivity"; // URL for keyboard search web page presented to user when they add a keyboard in the app. diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsActivity.java index b681fff7e0..10bd0f9c2c 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsActivity.java @@ -2,10 +2,12 @@ package com.tavultesoft.kmapro; import android.os.Bundle; +import com.tavultesoft.kmea.BaseActivity; + import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; -public class KeymanSettingsActivity extends AppCompatActivity { +public class KeymanSettingsActivity extends BaseActivity { protected static final String installedLanguagesKey = "InstalledLanguages"; protected static final String installKeyboardOrDictionaryKey = "InstallKeyboardOrDictionary"; protected static final String showBannerKey = "ShowBanner"; @@ -20,6 +22,7 @@ public class KeymanSettingsActivity extends AppCompatActivity { setContentView(R.layout.keyman_settings_layout); Toolbar toolbar = (Toolbar) findViewById(R.id.keyman_settings_toolbar); toolbar.setTitleTextColor(getResources().getColor(android.R.color.white)); + toolbar.setTitle(R.string.keyman_settings); setSupportActionBar(toolbar); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsFragment.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsFragment.java index fa15d4c1b9..468367f879 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsFragment.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsFragment.java @@ -1,3 +1,7 @@ +/** + * Copyright (C) 2020-2021 SIL International. All rights reserved. + */ + package com.tavultesoft.kmapro; import android.content.Context; @@ -12,6 +16,7 @@ import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; +import com.tavultesoft.kmea.DisplayLanguages; import com.tavultesoft.kmea.KMManager; import com.tavultesoft.kmea.data.Dataset; @@ -19,7 +24,7 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat { private static final String TAG = "SettingsFragment"; private static Context context; - private Preference languagesPreference, installKeyboardOrDictionary; + private Preference languagesPreference, installKeyboardOrDictionary, displayLanguagePreference; private CheckBoxPreference setSystemKeyboardPreference; private CheckBoxPreference setDefaultKeyboardPreference; @@ -46,6 +51,13 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat { Intent installIntent = new Intent(context, KeymanSettingsInstallActivity.class); installKeyboardOrDictionary.setIntent(installIntent); + displayLanguagePreference = new Preference(context); + displayLanguagePreference.setKey(DisplayLanguages.displayLanguageKey); + displayLanguagePreference.setTitle(getString(R.string.change_display_language)); + displayLanguagePreference.setWidgetLayoutResource(R.layout.preference_translate_icon_layout); + Intent displayLanguageIntent = new Intent(context, KeymanSettingsLocalizeActivity.class); + displayLanguagePreference.setIntent(displayLanguageIntent); + /* Automatically does the following: SharedPreferences.Editor editor = prefs.edit(); @@ -106,6 +118,7 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat { screen.addPreference(languagesPreference); screen.addPreference(installKeyboardOrDictionary); + screen.addPreference(displayLanguagePreference); screen.addPreference(setSystemKeyboardPreference); screen.addPreference(setDefaultKeyboardPreference); diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsLocalizeActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsLocalizeActivity.java new file mode 100644 index 0000000000..fae8c6f463 --- /dev/null +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeymanSettingsLocalizeActivity.java @@ -0,0 +1,106 @@ +/** + * Copyright (C) 2021 SIL International. All rights reserved. + */ + +package com.tavultesoft.kmapro; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Typeface; +import android.os.Bundle; +import android.view.View; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.preference.PreferenceManager; + +import com.tavultesoft.kmea.DisplayLanguages; + +import java.util.ArrayList; +import java.util.HashMap; + +public class KeymanSettingsLocalizeActivity extends AppCompatActivity { + private static final String TAG = "SettingsLocalizeActivity"; + private static ArrayList> localizeOptionList = null; + private static Typeface titleFont = null; + private static final String titleKey = "title"; + private static final String subtitleKey = "subtitle"; + private static final String iconKey = "icon"; + private static Context context; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + supportRequestWindowFeature(Window.FEATURE_NO_TITLE); + context = this; + + setContentView(R.layout.activity_list_layout); + final Toolbar toolbar = findViewById(R.id.list_toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + getSupportActionBar().setDisplayShowTitleEnabled(false); + + final ListView listView = findViewById(com.tavultesoft.kmea.R.id.listView); + + Bundle bundle = getIntent().getExtras(); + + final TextView textView = findViewById(R.id.bar_title); + textView.setText(getString(R.string.change_display_language)); + if (titleFont != null) { + textView.setTypeface(titleFont, Typeface.BOLD); + } + + localizeOptionList = new ArrayList<>(); + + final String noIcon = "0"; + for(DisplayLanguages.DisplayLanguageType l: DisplayLanguages.DisplayLanguages) { + HashMap hashMap = new HashMap<>(); + hashMap.put(titleKey, l.getLanguageName()); + hashMap.put(iconKey, noIcon); + localizeOptionList.add(hashMap); + } + + String[] from = new String[]{titleKey, subtitleKey, iconKey}; + int[] to = new int[]{com.tavultesoft.kmea.R.id.text1, com.tavultesoft.kmea.R.id.image1}; + + ListAdapter adapter = new SimpleAdapter(context, localizeOptionList, com.tavultesoft.kmea.R.layout.list_row_layout1, from, to) { + }; + listView.setAdapter(adapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + // Store the BCP-47 language tag in shared preference + if (position >= 0 && position < DisplayLanguages.DisplayLanguages.length) { + + DisplayLanguages.DisplayLanguageType l = DisplayLanguages.DisplayLanguages[position]; + String languageTag = l.getLanguageTag(); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(DisplayLanguages.displayLanguageKey, languageTag); + editor.commit(); + + // Restart the app to use selected locale + Intent intent = new Intent(context, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + } + }); + } + + @Override + public boolean onSupportNavigateUp() { + super.onBackPressed(); + return true; + } +} \ No newline at end of file diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java index 2585dcd520..b499d40fb7 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2018-2020 SIL International. All rights reserved. + * Copyright (C) 2018-2021 SIL International. All rights reserved. */ package com.tavultesoft.kmapro; @@ -17,6 +17,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.tavultesoft.kmea.BaseActivity; import com.tavultesoft.kmea.KMKeyboardDownloaderActivity; import com.tavultesoft.kmea.KMManager; import com.tavultesoft.kmea.KMManager.KeyboardType; @@ -38,7 +39,6 @@ import com.tavultesoft.kmea.util.KMPLink; import android.Manifest; import android.app.ProgressDialog; -import android.content.ComponentName; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; @@ -92,7 +92,7 @@ import android.widget.Toast; import io.sentry.android.core.SentryAndroid; -public class MainActivity extends AppCompatActivity implements OnKeyboardEventListener, OnKeyboardDownloadEventListener, +public class MainActivity extends BaseActivity implements OnKeyboardEventListener, OnKeyboardDownloadEventListener, ActivityCompat.OnRequestPermissionsResultCallback { public static Context context; @@ -256,13 +256,6 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this); PackageActivity.addKeyboardDownloadEventListener(this); - // Get calling activity - ComponentName component = this.getCallingActivity(); - String caller = null; - if (component != null) { - caller = component.getClassName(); - } - Intent intent = getIntent(); data = intent.getData(); @@ -285,10 +278,8 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi downloadKMP(scheme); break; case "keyman" : - // Only accept download links from Keyman browser activities - if (KMPLink.isKeymanDownloadLink(data.toString()) && caller != null && - (caller.equalsIgnoreCase("com.tavultesoft.kmea.KMPBrowserActivity") || - caller.equalsIgnoreCase("com.tavultesoft.kmapro.WebBrowserActivity"))) { + // TODO: Only accept download links from Keyman browser activities when universal links work + if (KMPLink.isKeymanDownloadLink(data.toString())) { // Convert opaque URI to hierarchical URI so the query parameters can be parsed Builder builder = new Uri.Builder(); @@ -298,6 +289,10 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi .encodedQuery(data.getEncodedQuery()); data = Uri.parse(builder.build().toString()); downloadKMP(scheme); + } else if (KMPLink.isLegacyKeymanDownloadLink(data.toString())) { + link = data.toString(); + data = KMPLink.getLegacyKeyboardDownloadLink(link); + downloadKMP(scheme); } else { String msg = "Unrecognized scheme: " + scheme; KMLog.LogError(TAG, msg); diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java index a2be8fd173..229b24fdb4 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java @@ -10,6 +10,7 @@ import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import com.tavultesoft.kmea.BaseActivity; import com.tavultesoft.kmea.KMManager; import com.tavultesoft.kmea.util.KMPLink; @@ -48,7 +49,7 @@ import androidx.appcompat.app.AppCompatActivity; import static android.app.Application.getProcessName; -public class WebBrowserActivity extends AppCompatActivity { +public class WebBrowserActivity extends BaseActivity { private static final String TAG = "WebBrowserActivity"; private WebView webView; private EditText addressField; diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-hdpi/ic_translate.png b/android/KMAPro/kMAPro/src/main/res/drawable-hdpi/ic_translate.png new file mode 100644 index 0000000000..20cf9715e0 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-hdpi/ic_translate.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-mdpi/ic_translate.png b/android/KMAPro/kMAPro/src/main/res/drawable-mdpi/ic_translate.png new file mode 100644 index 0000000000..20cf9715e0 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-mdpi/ic_translate.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-xhdpi/ic_translate.png b/android/KMAPro/kMAPro/src/main/res/drawable-xhdpi/ic_translate.png new file mode 100644 index 0000000000..3f804126c2 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-xhdpi/ic_translate.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-xxhdpi/ic_translate.png b/android/KMAPro/kMAPro/src/main/res/drawable-xxhdpi/ic_translate.png new file mode 100644 index 0000000000..71b2332aaa Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-xxhdpi/ic_translate.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-xxxhdpi/ic_translate.png b/android/KMAPro/kMAPro/src/main/res/drawable-xxxhdpi/ic_translate.png new file mode 100644 index 0000000000..0065c18426 Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-xxxhdpi/ic_translate.png differ diff --git a/android/KMAPro/kMAPro/src/main/res/layout/preference_translate_icon_layout.xml b/android/KMAPro/kMAPro/src/main/res/layout/preference_translate_icon_layout.xml new file mode 100644 index 0000000000..d66b445010 --- /dev/null +++ b/android/KMAPro/kMAPro/src/main/res/layout/preference_translate_icon_layout.xml @@ -0,0 +1,5 @@ + + diff --git a/android/KMAPro/kMAPro/src/main/res/values-ann/strings.xml b/android/KMAPro/kMAPro/src/main/res/values-ann/strings.xml new file mode 100644 index 0000000000..1ba8da1447 --- /dev/null +++ b/android/KMAPro/kMAPro/src/main/res/values-ann/strings.xml @@ -0,0 +1,122 @@ + + + + Che + + Òwọlọ olik-etip + + Okike inu-nge + + Ofifi + + Chọk inu-nge + + Etip + + Onineen̄ + + Wop aya inu + + Òsolek: %1$s + + Bene ge me ere keyi… + + + + Okike inu-nge: %1$d + + Rọ inu-nge imin + + Rọ inu-nge isip + + \nMêchọk otutuuk inu-nge\n + + Bene si ikwaan̄ + + Tap uwot-nge eyi usem kwun̄ + + Rọ mè Keyman ibene ikisi ikwaan̄ me otutuuk emen okwukwut + + Rọ Keyman ire ọ̀kpọọn̄ uwot-nge + + Ofifi etip + + Jeen̄ \"%1$s\" me ibebene + + Ufuna òkọt òwop ekwu, nyi Keyman unye mè ifuk/ige inu me okwukwut. + + Kpenyi unye ibe itap inu me emen ekwu. Ìkpokọt iwop ekwu uwot-nge + + Onineen̄ + + + Usem ewopbe (%1$d) + Ebi kè usem ewopbe (%1$d) + + + Wop Uwot-nge mè ìre Ikpa-usem + + Kijeen̄ egop mgbọ geelek + + Ọmọ me otitọt + + Ire iniin̄, jeen̄ mgbọ echieekbe ibe òjeen̄ ikọ òkinunu + + Tele ibe isa olik-etip iria etip òfolek ufialek ekwu + + Ire ichili ito, môria erip òfolek ufialek ekwu + + Ire ichit, ìkporia erip òfolek ufialek ekwu + + Bọkọ me keyman.com wop + + San̄a me emen okwukwut wop + + Bọkọ me ofifi okwukwut wop + + Tap usem sọkọ me lek uwot-nge ewopbe + + (inan̄a me ekwu eyi uwot-nge) + + Gobo Ekwu Uwot-nge + + Gobo usem nyi %1$s + + Mîtap usem %1$s me lek %2$s + + Mîwuuk lek itap otutuuk usem iso + + Wèek sà ìre ge iman̄ akpatan̄ + + Iman̄-ikpa + + Kpunu iman̄-ikpa + + Tap iman̄-ikpa + + Ibot + + Iman̄ akpatan̄ + + Kpekọt iwop ekwu %1$s + + Mêkibọkọ ekwu uwot-nge itap\n%1$s… + + Kpekọt isan̄a isibi + + Wop Uwot-nge + + Onu me %1$s + + Wop Ikpa-usem + + Ekwu uwot-nge ìkakaan̄ uwot-nge ekichabe ubọk eyi mêkọtbe iwop + + Kpunu aya ikọ òkinunu eyi mêwopbe + + Kpunu uwot-nge sà ìre aya ikọ òkinunu eyi mêwopbe + + Uwot-nge ìkakaan̄ usem òje me lek eyi mêkọtbe iwop + + Metadata òkup me ekwu îlọ/îchep + diff --git a/android/KMAPro/kMAPro/src/main/res/values-de-rDE/strings.xml b/android/KMAPro/kMAPro/src/main/res/values-de-rDE/strings.xml new file mode 100644 index 0000000000..71767f4fa8 --- /dev/null +++ b/android/KMAPro/kMAPro/src/main/res/values-de-rDE/strings.xml @@ -0,0 +1,122 @@ + + + + Teilen + + Web-Browser + + Schriftgröße + + Mehr + + Text löschen + + Info + + Einstellungen + + Updates installieren + + Version: %1$s + + Tippen Sie hier… + + + + Textgröße: %1$d + + Text größer + + Text kleiner + + \nDer gesamte Text wird gelöscht\n + + Erste Schritte + + Tastatur für Ihre Sprache hinzufügen + + Keyman als systemweite Tastatur aktivieren + + Keyman als Standard-Tastatur festlegen + + Weitere Informationen + + Zeige \"%1$s\" beim Start + + Um Tastaturpakete zu installieren, braucht Keyman die Berechtigung zum Lesen/Schreiben. + + Zugriff auf den Speicher wurde abgelehnt. Möglicherweise funktioniert die Installation des Tastaturpakets nicht korrekt + + Einstellungen + + + Installierte Sprachen (%1$d) + Installierte Sprachen (%1$d) + + + Tastatur oder Wörterbuch installieren + + Banner immer anzeigen + + Nicht implementiert + + Wenn ausgeschaltet, wird nur angezeigt, wenn vorhersagender Text aktiviert ist + + Erlaube das Senden von Fehlerberichten + + Wenn aktiviert werden Fehlerberichte gesendet + + Wenn deaktiviert werden Fehlerberichte nicht gesendet + + Von keyman.com installieren + + Aus lokaler Datei installieren + + Von einem anderen Gerät installieren + + Sprachen zur installierten Tastatur hinzufügen + + (von Tastaturpaket) + + Tastaturpaket auswählen + + Wählen Sie Sprachen für %1$s + + Sprache %1$s zu %2$s hinzugefügt + + Alle Sprachen bereits installiert + + Suchen oder URL eingeben + + Lesezeichen + + Keine Lesezeichen + + Lesezeichen hinzufügen + + Titel + + Url + + Paket %1$s konnte nicht installiert werden + + Tastaturpaket wird heruntergeladen\n%1$s… + + Entpacken fehlgeschlagen + + Tastatur installieren + + Willkommen bei %1$s + + Wörterbuch installieren + + Tastaturpaket enthält keine berührungsoptimierte Tastatur, die installiert werden könnte + + Kein neues Wörterbuch zu installieren + + Keine Tastaturen oder Wörterbücher zu installieren + + Tastaturpaket enthält keine zugehörigen Sprachen, die installiert werden könnten + + Ungültige Metadaten im Paket + diff --git a/android/KMAPro/kMAPro/src/main/res/values/strings.xml b/android/KMAPro/kMAPro/src/main/res/values/strings.xml index 8784919a06..1285c9f2e7 100644 --- a/android/KMAPro/kMAPro/src/main/res/values/strings.xml +++ b/android/KMAPro/kMAPro/src/main/res/values/strings.xml @@ -95,6 +95,9 @@ Install Keyboard or Dictionary + + Change display language + Always show banner diff --git a/android/KMEA/app/build.gradle b/android/KMEA/app/build.gradle index 20c23e8aa0..d5b7348f28 100644 --- a/android/KMEA/app/build.gradle +++ b/android/KMEA/app/build.gradle @@ -66,6 +66,7 @@ dependencies { implementation 'com.google.android.material:material:1.2.1' implementation 'commons-io:commons-io:2.6' implementation 'io.sentry:sentry-android:3.1.0' + implementation 'androidx.preference:preference:1.1.1' // Robolectric testImplementation 'androidx.test:core:1.2.0' diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/BaseActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/BaseActivity.java new file mode 100644 index 0000000000..fdd8ed2de1 --- /dev/null +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/BaseActivity.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2021 SIL International. All rights reserved. + */ + +package com.tavultesoft.kmea; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.SharedPreferences; +import android.os.Build; +import android.os.LocaleList; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.preference.PreferenceManager; + +import com.tavultesoft.kmea.util.ContextUtils; + +import java.util.Locale; + +public class BaseActivity extends AppCompatActivity { + + @Override + protected void attachBaseContext(Context newBase) { + // Override the app locale using the BCP 47 tag from shared preferences + // Using PreferenceManager because this is before onCreate() + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newBase); + String languageTag = prefs.getString(DisplayLanguages.displayLanguageKey, DisplayLanguages.unspecifiedLocale); + Locale localeToSwitchTo; + if (languageTag == null || languageTag.equals(DisplayLanguages.unspecifiedLocale)) { + // If display language not specified, use the default locale + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + super.attachBaseContext(newBase); + return; + } + localeToSwitchTo = LocaleList.getDefault().get(0); + } else { + localeToSwitchTo = Locale.forLanguageTag(languageTag); + } + ContextWrapper localeUpdatedContext = ContextUtils.updateLocale(newBase, localeToSwitchTo); + super.attachBaseContext(localeUpdatedContext); + } + +} diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/DisplayLanguages.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/DisplayLanguages.java new file mode 100644 index 0000000000..7ffc3e511d --- /dev/null +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/DisplayLanguages.java @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2021 SIL International. All rights reserved. + */ + +package com.tavultesoft.kmea; + +public class DisplayLanguages { + private static final String TAG = "DisplayLanguages"; + public static final String displayLanguageKey = "DisplayLanguage"; + public static final String unspecifiedLocale = ""; // empty string for app to use device's default locale + + public static class DisplayLanguageType { + String languageTag; + String languageName; + + public DisplayLanguageType(String languageTag, String languageName) { + this.languageTag = languageTag; + this.languageName = languageName; + } + + public String getLanguageTag() { + return this.languageTag; + } + + public String getLanguageName() { + return this.languageName; + } + } + + // Display Language types (as named in translate.keyman.com) + // Order doesn't matter since we're storing BCP-47 tags in the settings preference + public static final DisplayLanguageType[] DisplayLanguages = + { + new DisplayLanguageType(unspecifiedLocale, "Default Locale"), + new DisplayLanguageType("de-DE", "German"), + new DisplayLanguageType("km-KH", "Khmer"), + new DisplayLanguageType("ann", "Obolo") + }; + +} diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java index cd56cf6bc7..c55138ad35 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java @@ -22,7 +22,7 @@ import java.util.List; import static com.tavultesoft.kmea.ConfirmDialogFragment.DialogType.DIALOG_TYPE_DOWNLOAD_KEYBOARD; import static com.tavultesoft.kmea.ConfirmDialogFragment.DialogType.DIALOG_TYPE_DOWNLOAD_MODEL; -public class KMKeyboardDownloaderActivity extends AppCompatActivity { +public class KMKeyboardDownloaderActivity extends BaseActivity { // Bundle Keys // Cloud diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 729d5d2cfb..9365a1bb15 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -420,21 +420,19 @@ public final class KMManager { * @param keyboard KeyboardType * @return RelativeLayout.LayoutParams */ - private static RelativeLayout.LayoutParams getKeyboardLayoutParams(KeyboardType keyboard) { + private static RelativeLayout.LayoutParams getKeyboardLayoutParams() { int bannerHeight = getBannerHeight(appContext); int kbHeight = getKeyboardHeight(appContext); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.MATCH_PARENT, bannerHeight + kbHeight); - if (keyboard == KeyboardType.KEYBOARD_TYPE_INAPP) { - params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); - } + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); return params; } private static void initInAppKeyboard(Context appContext) { if (InAppKeyboard == null) { InAppKeyboard = new KMKeyboard(appContext, KeyboardType.KEYBOARD_TYPE_INAPP); - RelativeLayout.LayoutParams params = getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_INAPP); + RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); InAppKeyboard.setLayoutParams(params); InAppKeyboard.setVerticalScrollBarEnabled(false); InAppKeyboard.setHorizontalScrollBarEnabled(false); @@ -447,7 +445,7 @@ public final class KMManager { private static void initSystemKeyboard(Context appContext) { if (SystemKeyboard == null) { SystemKeyboard = new KMKeyboard(appContext, KeyboardType.KEYBOARD_TYPE_SYSTEM); - RelativeLayout.LayoutParams params = getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_SYSTEM); + RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); SystemKeyboard.setLayoutParams(params); SystemKeyboard.setVerticalScrollBarEnabled(false); SystemKeyboard.setHorizontalScrollBarEnabled(false); @@ -537,12 +535,12 @@ public final class KMManager { public static void onConfigurationChanged(Configuration newConfig) { // KMKeyboard if (InAppKeyboard != null) { - RelativeLayout.LayoutParams params = getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_INAPP); + RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); InAppKeyboard.setLayoutParams(params); InAppKeyboard.onConfigurationChanged(newConfig); } if (SystemKeyboard != null) { - RelativeLayout.LayoutParams params = getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_SYSTEM); + RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); SystemKeyboard.setLayoutParams(params); SystemKeyboard.onConfigurationChanged(newConfig); } @@ -723,7 +721,7 @@ public final class KMManager { * * At some point, we might migrate /cloud/ keyboards into packages * 5) For now, delete cloud/sil_euro_latin*.js - * + * * Assumption: No legacy keyboards exist in /packages/*.js * @param context */ @@ -1061,12 +1059,12 @@ public final class KMManager { RelativeLayout.LayoutParams params; if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreTextChange) { - params = getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_INAPP); + params = getKeyboardLayoutParams(); InAppKeyboard.setLayoutParams(params); InAppKeyboard.loadJavascript(String.format("enableSuggestions(%s, %s, %s)", model, mayPredict, mayCorrect)); } if (SystemKeyboard != null && SystemKeyboardLoaded && !SystemKeyboardShouldIgnoreTextChange) { - params = getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_SYSTEM); + params = getKeyboardLayoutParams(); SystemKeyboard.setLayoutParams(params); SystemKeyboard.loadJavascript(String.format("enableSuggestions(%s, %s, %s)", model, mayPredict, mayCorrect)); } @@ -1278,9 +1276,9 @@ public final class KMManager { currentBanner = KMManager.KM_BANNER_STATE_BLANK; if(result1) - InAppKeyboard.setLayoutParams(getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_INAPP)); + InAppKeyboard.setLayoutParams(getKeyboardLayoutParams()); if(result2) - SystemKeyboard.setLayoutParams(getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_SYSTEM)); + SystemKeyboard.setLayoutParams(getKeyboardLayoutParams()); } registerAssociatedLexicalModel(languageID); @@ -2005,7 +2003,7 @@ public final class KMManager { } currentBanner = (isModelActive && modelPredictionPref) ? KM_BANNER_STATE_SUGGESTION : KM_BANNER_STATE_BLANK; - RelativeLayout.LayoutParams params = getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_INAPP); + RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); InAppKeyboard.setLayoutParams(params); } else if (url.indexOf("suggestPopup") >= 0) { // URL has actual path to the keyboard.html file as a prefix! We need to replace @@ -2273,7 +2271,7 @@ public final class KMManager { } currentBanner = (isModelActive && modelPredictionPref) ? KM_BANNER_STATE_SUGGESTION : KM_BANNER_STATE_BLANK; - RelativeLayout.LayoutParams params = getKeyboardLayoutParams(KeyboardType.KEYBOARD_TYPE_SYSTEM); + RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); SystemKeyboard.setLayoutParams(params); } else if (url.indexOf("suggestPopup") >= 0) { // URL has actual path to the keyboard.html file as a prefix! We need to replace diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardInfoActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardInfoActivity.java index 63f95182ab..4c2a316e96 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardInfoActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardInfoActivity.java @@ -36,7 +36,7 @@ import com.tavultesoft.kmea.util.MapCompat; import com.tavultesoft.kmea.util.QRCodeUtil; // Public access is necessary to avoid IllegalAccessException -public final class KeyboardInfoActivity extends AppCompatActivity { +public final class KeyboardInfoActivity extends BaseActivity { private static final String TAG = "KeyboardInfoActivity"; private static Toolbar toolbar = null; diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java index 5da07ec094..960e29a08f 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java @@ -45,7 +45,7 @@ import android.widget.Toast; import androidx.appcompat.widget.Toolbar; -public final class KeyboardPickerActivity extends AppCompatActivity { +public final class KeyboardPickerActivity extends BaseActivity { //TODO: view instances should not be static private static Toolbar toolbar = null; diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelInfoActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelInfoActivity.java index 7213a2cd68..80f45ed553 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelInfoActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelInfoActivity.java @@ -38,7 +38,7 @@ import com.tavultesoft.kmea.util.MapCompat; import static com.tavultesoft.kmea.ConfirmDialogFragment.DialogType.DIALOG_TYPE_DELETE_MODEL; // Public access is necessary to avoid IllegalAccessException -public final class ModelInfoActivity extends AppCompatActivity { +public final class ModelInfoActivity extends BaseActivity { private static ArrayList> infoList = null; private final String titleKey = "title"; diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java index 741a1eb8d3..a4d03ef3ad 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java @@ -40,7 +40,7 @@ import java.util.Map; * Gets the list of installable lexical models from Keyman cloud and allows user to download a model. * Displays a list of available models for a language ID. */ -public final class ModelPickerActivity extends AppCompatActivity { +public final class ModelPickerActivity extends BaseActivity { private Context context; private static Toolbar toolbar = null; diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/ContextUtils.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/ContextUtils.java new file mode 100644 index 0000000000..c432dfa63b --- /dev/null +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/ContextUtils.java @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2021 SIL International. All rights reserved. + */ +package com.tavultesoft.kmea.util; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Build; +import android.os.LocaleList; + +import java.util.Locale; + +/** + * Class to programmatically change the application locale (#4236) + * References + * Tutorial from https://lokalise.com/blog/android-app-localization/#Change_Application_Locale_Programmatically + * https://github.com/nirm2009/lokalise/tree/master/android-i18n + * https://stackoverflow.com/questions/39705739/android-n-change-language-programmatically + */ +public class ContextUtils extends ContextWrapper { + public ContextUtils(Context base) { + super(base); + } + + public static ContextWrapper updateLocale(Context context, Locale localeToSwitchTo) { + Resources resources = context.getResources(); + Configuration configuration = resources.getConfiguration(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + LocaleList localeList = new LocaleList(localeToSwitchTo); + LocaleList.setDefault(localeList); + configuration.setLocales(localeList); + } else { + configuration.locale = localeToSwitchTo; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + context = context.createConfigurationContext(configuration); + } else { + resources.updateConfiguration(configuration, resources.getDisplayMetrics()); + } + + return new ContextUtils(context); + } + +} diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/KMPLink.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/KMPLink.java index 5086b9d8b6..80e7c16a12 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/KMPLink.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/KMPLink.java @@ -35,6 +35,9 @@ public final class KMPLink { KMP_STAGING_HOST); private static final Pattern downloadPattern = Pattern.compile(downloadPatternFormatStr); + private static final String LEGACY_DOWNLOAD_KEYBOARDS_PATTERN_FORMATSTR = "^keyman://localhost/open\\?(.+)?$"; + private static final Pattern legacyDownloadPattern = Pattern.compile(LEGACY_DOWNLOAD_KEYBOARDS_PATTERN_FORMATSTR); + // Keyman 14.0+ generated URL for keyboard download links private static final String KMP_DOWNLOAD_KEYBOARDS_FORMATSTR = "https://%s/go/package/download/%s"; @@ -74,6 +77,29 @@ public final class KMPLink { return status; } + /** + * Check if a URL is a valid legacy Keyman keyboard download link (uses keyman://) + * @param url String of the URL to parse + * @return boolean + */ + public static boolean isLegacyKeymanDownloadLink(String url) { + boolean status = false; + if (url == null || url.isEmpty()) { + return status; + } + Matcher legacyMatcher = legacyDownloadPattern.matcher(url); + if (legacyMatcher.matches() && legacyMatcher.group(1) != null) { + Uri data = Uri.parse(url); + String keyboard = data.getQueryParameter("keyboard"); + String language = data.getQueryParameter("language"); + if (keyboard != null && !keyboard.isEmpty()) { + status = true; + } + } + + return status; + } + /** * Get the keyman.com host (production vs staging) based on the tier * @return String of keyman.com host @@ -130,4 +156,45 @@ public final class KMPLink { return uri; } + + /** + * Parses a URL and generates the Keyman keyboard download link. URL contains: + * keyboard (required) + * language (optional) + * @param url String of the URL to parse + * @return Uri of the Keyman keyboard download link + */ + public static Uri getLegacyKeyboardDownloadLink(String url) { + Uri uri = null; + + if (url == null || url.isEmpty()) { + return uri; + } + + Matcher matcher = legacyDownloadPattern.matcher(url); + // Validate deep link with package ID and optional bcp47 tag + if (matcher.matches() && matcher.group(1) != null) { + Uri installUri = Uri.parse(url); + String tier = KMManager.getTier(BuildConfig.VERSION_NAME).toString().toLowerCase(); + String host = (tier.equals("alpha") || tier.equals("beta")) ? KMP_STAGING_HOST : KMP_PRODUCTION_HOST; + String keyboardID = installUri.getQueryParameter("keyboard"); + String languageID = installUri.getQueryParameter("language"); + + String downloadURL = String.format(KMP_DOWNLOAD_KEYBOARDS_FORMATSTR, + host, + keyboardID); // Using keyboardID instead of packageID + uri = Uri.parse(downloadURL) + .buildUpon() + .appendQueryParameter(KMKeyboardDownloaderActivity.KMKey_Platform, "android") + .appendQueryParameter(KMKeyboardDownloaderActivity.KMKey_Tier, tier) + .build(); + if (languageID != null) { + uri = uri.buildUpon() + .appendQueryParameter(KMKeyboardDownloaderActivity.KMKey_BCP47, languageID) + .build(); + } + } + + return uri; + } } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/ZipUtils.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/ZipUtils.java index e429cf4426..3344534956 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/ZipUtils.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/util/ZipUtils.java @@ -1,3 +1,7 @@ +/** + * Copyright (C) 2021 SIL International. All rights reserved. + */ + package com.tavultesoft.kmea.util; import java.io.BufferedInputStream; @@ -9,11 +13,9 @@ import java.io.IOException; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -/** - * Created by joshua on 12/11/2017. - */ - public class ZipUtils { + private final static String TAG = "ZipUtils"; + // Credit to zapi's answer at https://stackoverflow.com/questions/3382996/how-to-unzip-files-programmatically-in-android. public static void unzip(File zipFile, File targetDirectory) throws IOException { ZipInputStream zis = new ZipInputStream( @@ -24,6 +26,15 @@ public class ZipUtils { byte[] buffer = new byte[8192]; while ((ze = zis.getNextEntry()) != null) { File file = new File(targetDirectory, ze.getName()); + + // Check for zip path traversal vulnerability + // https://support.google.com/faqs/answer/9294009 + String canonicalPath = file.getCanonicalPath(); + if (!canonicalPath.startsWith(targetDirectory.getCanonicalPath())) { + // Security exception + throw new SecurityException("Zip traversal error"); + } + File dir = ze.isDirectory() ? file : file.getParentFile(); if (!dir.isDirectory() && !dir.mkdirs()) throw new FileNotFoundException("Failed to ensure directory: " + diff --git a/android/KMEA/app/src/main/res/values-ann/strings.xml b/android/KMEA/app/src/main/res/values-ann/strings.xml new file mode 100644 index 0000000000..5a73b08c3d --- /dev/null +++ b/android/KMEA/app/src/main/res/values-ann/strings.xml @@ -0,0 +1,131 @@ + + + + + + + Uwot-nge + Ebi kè uwot-nge + + + Tap aya uwot-nge gbaalek + + Ebi kè usem ewopbe + + %1$s Onineen̄ + + Tap sọkọ + + Gwu kom + + Gwak + + Chit + + Chit Keyman + + Bọkọ tap + + Wop + + Ofifi mgbọ + + Eyi ògọọk + + ÎSO + + Bọkọ aya + + \nKpekọt itibi itet akpatan̄ Keyman!\n + + Ìre oweek ichọchọk uwot-nge yi isan̄a? + + Ìre oweek ibọbọkọ aya òsolek uwot-nge yi itap? + + Ìre owu môma inwenwene uwot-nge mè ikpa-usem itap me eyi ayaya mgbọ keyi? + + Irọrọ inu-ikwaan̄ iso usen + + Aya inu-ikwaan̄ ọmọ wa + + %1$s (Aya Ọmọwa) + + Aya Uwot-nge Ọmọwa %1$s: %2$s + + Aya Ikpa-usem Ọmọwa %1$s: %2$s + + Òsolek uwot-nge + + Ugọbọ ntap-ubọk + + Jibi uwot-nge + + [aya] %1$s + + Gwuku iman̄ yi kè òbọkọ\nuwot-nge yi me ofifi okwukwut + + Wèek ikpa-usem òje me lek bọkọ tap + + Ìre oweek ibọbọkọ aya òsolek ikpa-usem yi itap? + + Kpunu ikpa-usem mêbọkọbe itap + + Kpunu onineen̄ inu-ikwaan̄ + + Mîbene ikirọ inu-ikwaan̄ iso usen me udun̄-oyet + + Mêkibọkọ onineen̄ inu-ikwaan̄ itap; soso yaka sa me mgbidim mgbọ! + + Mêkiweek inu-ikwaan̄ + + Ibọbọkọ uwot-nge itap îbene me Udun̄ + + Mîwuuk lek ibene ikibọkọ uwot-nge egobobe ya itap; soso neke sa lek me mgbidim mgbọ! + + Mîbọkọ uwot-nge itap inan̄a! + + Ibọbọkọ ikpa-usem itap îbene me Udun̄ + + Mîwuuk lek ibene ikibọkọ ikpa-usem egobobe ya itap; soso neke sa lek me mgbidim mgbọ! + + Mîbọkọ ikpa-usem itap inan̄a. + + Kpekọt ibọkọ etip me akpatan̄! + + "Otutuuk inu-ikwaan̄ mîso usen!" + + Òsolek Ikpa-usem + + Jibi ikpa-usem + + Ìre oweek ichọchọk ikpa-usem yi isan̄a? + + Mîbọkọ uwot-nge %1$s itap + + Rọ ikinen̄e ige + + Rọ ikibak ikọ onu-misi + + Ikpa-usem + + Kpọ ikpa-usem òkukup + + Ikpa-usem: %1$s + + Ikpa-usem %1$s + + + Ikpa-usem ebọkọbe itap + + + (uwot-nge %1$d) + (Ebi kè uwot-nge %1$d) + + + + + Chọk + + + Chak ubọk me ere keyi sa nwene uwot-nge + diff --git a/android/KMEA/app/src/main/res/values-de-rDE/strings.xml b/android/KMEA/app/src/main/res/values-de-rDE/strings.xml new file mode 100644 index 0000000000..b9a06bd466 --- /dev/null +++ b/android/KMEA/app/src/main/res/values-de-rDE/strings.xml @@ -0,0 +1,131 @@ + + + + + + + Tastatur + Tastaturen + + + Neue Tastatur hinzufügen + + Installierte Sprachen + + %1$s Einstellungen + + Hinzufügen + + Zurück + + Abbrechen + + Schließen + + Keyman schließen + + Herunterladen + + Installieren + + Später + + Weiter + + Ok + + Aktualisieren + + \nKeine Verbindung zum Keyman Server!\n + + Möchten Sie diese Tastatur löschen? + + Möchten Sie die neueste Version dieser Tastatur herunterladen? + + Möchten Sie Tastaturen und Wörterbücher jetzt aktualisieren? + + Ressourcen Updates + + Ressourcen Updates verfügbar + + %1$s (Update verfügbar) + + Updates für Tastatur %1$s verfügbar: %2$s + + Updates für Wörterbuch %1$s verfügbar: %2$s + + Tastaturversion + + Hilfe-Link + + Tastatur deinstallieren + + [neu] %1$s + + Scannen Sie diesen Code, um diese\nTastatur auf einem anderen Gerät zu laden + + Suche nach zugehörigem Wörterbuch zum Herunterladen + + Möchten Sie die neueste Version dieses Wörterbuchs herunterladen? + + Kein Wörterbuch zum Herunterladen + + Der Ressourcenkatalog ist nicht verfügbar + + Katalogaktualisierung im Hintergrund gestartet + + Der Katalog wird noch heruntergeladen. Bitte versuchen Sie es gleich nochmal! + + Suche nach Ressource + + Das Herunterladen der Tastatur wurde im Hintergrund gestartet + + Die ausgewählte Tastatur wird bereits heruntergeladen. Bitte versuchen Sie es gleich nochmal! + + Download der Tastatur ist abgeschlossen! + + Das Herunterladen des Wörterbuchs wurde im Hintergrund gestartet + + Das ausgewählte Wörterbuch wird bereits heruntergeladen. Bitte versuchen Sie es gleich nochmal! + + Download des Wörterbuchs ist abgeschlossen. + + Fehler beim Zugriff auf den Server! + + "Alle Ressourcen sind auf dem neuesten Stand!" + + Wörterbuchversion + + Wörterbuch deinstallieren + + Möchten Sie dieses Wörterbuch löschen? + + %1$s -Tastatur installiert + + Korrekturen aktivieren + + Vorhersagen aktivieren + + Wörterbuch + + Auf verfügbares Wörterbuch prüfen + + Wörterbuch: %1$s + + %1$s Wörterbücher + + + Wörterbuch installiert + + + (%1$d Tastatur) + (%1$d Tastaturen) + + + + + Entfernen + + + Hier tippen, um Tastatur zu ändern + diff --git a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/util/ZipUtilsTest.java b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/util/ZipUtilsTest.java new file mode 100644 index 0000000000..41c0f36818 --- /dev/null +++ b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/util/ZipUtilsTest.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2021 SIL International. All rights reserved. + */ + +package com.tavultesoft.kmea.util; + +import com.tavultesoft.kmea.util.ZipUtils; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.io.File; +import java.io.IOException; + +public class ZipUtilsTest { + private static final File TEST_RESOURCE_ROOT = new File("test_resources"); + private static final File TEST_EXTRACTION_ROOT = new File(TEST_RESOURCE_ROOT, "temp"); + + // Zip file with Windows paths to test zip slip vulnerability + private static final File TEST_ZIP_SLIP_FILE = new File(TEST_RESOURCE_ROOT, "zip-slip-win.zip"); + + @Rule + public ExpectedException exceptionRule = ExpectedException.none(); + + @Test + public void test_unzip_throwsSecurityException() throws SecurityException, IOException { + // Zip file for testing zip slip vulnerability has Windows paths + Assume.assumeTrue(System.getProperty("os.name").toLowerCase().startsWith("win")); + + exceptionRule.expect(SecurityException.class); + exceptionRule.expectMessage("Zip traversal error"); + ZipUtils.unzip(TEST_ZIP_SLIP_FILE, TEST_EXTRACTION_ROOT); + } +} diff --git a/android/KMEA/test_resources/zip-slip-win.zip b/android/KMEA/test_resources/zip-slip-win.zip new file mode 100644 index 0000000000..33847ad920 Binary files /dev/null and b/android/KMEA/test_resources/zip-slip-win.zip differ diff --git a/android/Samples/KMSample1/app/build.gradle b/android/Samples/KMSample1/app/build.gradle index 645cb3f585..c0737f1b2b 100644 --- a/android/Samples/KMSample1/app/build.gradle +++ b/android/Samples/KMSample1/app/build.gradle @@ -1,4 +1,7 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' + id 'io.sentry.android.gradle' +} android { compileSdkVersion 29 @@ -40,5 +43,5 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.3.0-alpha02' implementation 'com.google.android.material:material:1.2.1' api(name: 'keyman-engine', ext: 'aar') - implementation 'io.sentry:sentry-android:2.3.0' + implementation 'io.sentry:sentry-android:3.1.0' } diff --git a/android/Samples/KMSample1/build.gradle b/android/Samples/KMSample1/build.gradle index 587e3d747f..522033b204 100644 --- a/android/Samples/KMSample1/build.gradle +++ b/android/Samples/KMSample1/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.6.1' - classpath 'io.sentry:sentry-android:2.0.1' + classpath 'io.sentry:sentry-android-gradle-plugin:1.7.36' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/android/Samples/KMSample2/app/build.gradle b/android/Samples/KMSample2/app/build.gradle index 1efd687137..2334fe1beb 100644 --- a/android/Samples/KMSample2/app/build.gradle +++ b/android/Samples/KMSample2/app/build.gradle @@ -1,4 +1,7 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' + id 'io.sentry.android.gradle' +} android { compileSdkVersion 29 @@ -39,5 +42,5 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.3.0-alpha02' implementation 'com.google.android.material:material:1.2.1' api (name:'keyman-engine', ext:'aar') - implementation 'io.sentry:sentry-android:2.3.0' + implementation 'io.sentry:sentry-android:3.1.0' } diff --git a/android/Samples/KMSample2/app/src/main/java/com/keyman/kmsample2/SystemKeyboard.java b/android/Samples/KMSample2/app/src/main/java/com/keyman/kmsample2/SystemKeyboard.java index 36f8ec72dc..e2192bc9f9 100644 --- a/android/Samples/KMSample2/app/src/main/java/com/keyman/kmsample2/SystemKeyboard.java +++ b/android/Samples/KMSample2/app/src/main/java/com/keyman/kmsample2/SystemKeyboard.java @@ -14,11 +14,13 @@ import java.util.HashMap; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; +import android.widget.FrameLayout; public class SystemKeyboard extends InputMethodService implements OnKeyboardEventListener { @@ -157,6 +159,16 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven KMManager.onConfigurationChanged(newConfig); } + @Override + public void onConfigureWindow(Window win, boolean isFullscreen, boolean isCandidatesOnly) { + super.onConfigureWindow(win, isFullscreen, isCandidatesOnly); + + // We don't currently use isFullscreen or isCandidatesOnly; we always want to MATCH_PARENT, + // unlike the default for height which is WRAP_CONTENT. We then adjust the touchable area + // in `onCalculateInsets` + win.setLayout(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + } + @Override public void onComputeInsets(InputMethodService.Insets outInsets) { super.onComputeInsets(outInsets); @@ -173,6 +185,7 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven int bannerHeight = KMManager.getBannerHeight(this); int kbHeight = KMManager.getKeyboardHeight(this); outInsets.contentTopInsets = inputViewHeight - bannerHeight - kbHeight; + outInsets.visibleTopInsets = outInsets.contentTopInsets; outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; outInsets.touchableRegion.set(0, outInsets.contentTopInsets, size.x, size.y); } diff --git a/android/Samples/KMSample2/build.gradle b/android/Samples/KMSample2/build.gradle index 587e3d747f..522033b204 100644 --- a/android/Samples/KMSample2/build.gradle +++ b/android/Samples/KMSample2/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.6.1' - classpath 'io.sentry:sentry-android:2.0.1' + classpath 'io.sentry:sentry-android-gradle-plugin:1.7.36' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/android/Tests/KeyboardHarness/app/build.gradle b/android/Tests/KeyboardHarness/app/build.gradle index 5cc2e4d704..7a443d8db8 100644 --- a/android/Tests/KeyboardHarness/app/build.gradle +++ b/android/Tests/KeyboardHarness/app/build.gradle @@ -1,4 +1,7 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' + id 'io.sentry.android.gradle' +} ext.rootPath = '../../../' apply from: "$rootPath/version.gradle" @@ -46,5 +49,5 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.3.0-alpha02' implementation 'com.google.android.material:material:1.2.1' api (name:'keyman-engine', ext:'aar') - implementation 'io.sentry:sentry-android:2.3.0' + implementation 'io.sentry:sentry-android:3.1.0' } diff --git a/android/Tests/KeyboardHarness/build.gradle b/android/Tests/KeyboardHarness/build.gradle index 587e3d747f..522033b204 100644 --- a/android/Tests/KeyboardHarness/build.gradle +++ b/android/Tests/KeyboardHarness/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.6.1' - classpath 'io.sentry:sentry-android:2.0.1' + classpath 'io.sentry:sentry-android-gradle-plugin:1.7.36' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/common/core/desktop/src/kmx/kmx_processor.cpp b/common/core/desktop/src/kmx/kmx_processor.cpp index eb189f4ed8..be513aef4d 100644 --- a/common/core/desktop/src/kmx/kmx_processor.cpp +++ b/common/core/desktop/src/kmx/kmx_processor.cpp @@ -20,6 +20,7 @@ KMX_BOOL km::kbp::kmx::g_silent = FALSE; KMX_Processor::KMX_Processor() : m_actions(&m_context), m_options(&m_keyboard) { m_indexStack = new KMX_WORD[GLOBAL_ContextStackSize]; m_miniContext = new KMX_WCHAR[GLOBAL_ContextStackSize]; + m_miniContextIfLen = 0; } KMX_Processor::~KMX_Processor() { @@ -242,6 +243,8 @@ KMX_BOOL KMX_Processor::ProcessGroup(LPGROUP gp, KMX_BOOL *pOutputKeystroke) assert(kkp != NULL); + m_miniContextIfLen = xstrlen(kkp->dpContext) - xstrlen_ignoreifopt(kkp->dpContext); + // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support if(*kkp->dpContext == UC_SENTINEL && *(kkp->dpContext+1) == CODE_NUL) u16cpy(m_miniContext, /*GLOBAL_ContextStackSize,*/ m_context.Buf(xstrlen_ignoreifopt(kkp->dpContext)-1) /*, GLOBAL_ContextStackSize*/); // I3162 // I3536 @@ -353,18 +356,18 @@ int KMX_Processor::PostString(PKMX_WCHAR str, LPKEYBOARD lpkb, PKMX_WCHAR endstr m_actions.QueueAction(QIT_BELL, 0); break; case CODE_CONTEXT: // copy the context to the output - for(q = m_miniContext; *q; q++) { - m_actions.QueueAction(QIT_CHAR, *q); - } + { + KMX_BOOL ignoreOutputKeystroke; + PostString(m_miniContext, lpkb, (PKMX_WCHAR) u16chr(m_miniContext, 0), &ignoreOutputKeystroke); break; + } case CODE_CONTEXTEX: p++; - for(q = m_miniContext, i = 0; *q && i < *p-1; i++, q=incxstr(q)); - if(*q) { - m_actions.QueueAction(QIT_CHAR, *q); - if(Uni_IsSurrogate1(*q) && Uni_IsSurrogate2(*(q+1))) { - m_actions.QueueAction(QIT_CHAR, *(q+1)); - } + for (q = m_miniContext, i = m_miniContextIfLen; *q && i < *p - 1; i++, q = incxstr(q)); + if (*q) { + KMX_BOOL ignoreOutputKeystroke; + temp = incxstr(q); + PostString(q, lpkb, temp, &ignoreOutputKeystroke); } break; case CODE_RETURN: // stop processing and start PostAllKeys diff --git a/common/core/desktop/src/kmx/kmx_processor.h b/common/core/desktop/src/kmx/kmx_processor.h index f541c69f60..52ec63b889 100644 --- a/common/core/desktop/src/kmx/kmx_processor.h +++ b/common/core/desktop/src/kmx/kmx_processor.h @@ -28,6 +28,7 @@ class KMX_Processor { private: PKMX_WORD m_indexStack; PKMX_WCHAR m_miniContext; + int m_miniContextIfLen; // number of if() statements excluded from start of m_miniContext KMSTATE m_state; km_kbp_state *m_kbp_state; diff --git a/common/core/desktop/tests/unit/kmx/044 - if and context.kmn b/common/core/desktop/tests/unit/kmx/044 - if and context.kmn new file mode 100644 index 0000000000..98f4bf9853 --- /dev/null +++ b/common/core/desktop/tests/unit/kmx/044 - if and context.kmn @@ -0,0 +1,19 @@ +c Description: Tests that context(x) takes if() statements into account. See #4275. +c keys: [K_A][K_B] +c expected: ex +c context: + +store(&version) '10.0' + +begin Unicode > use(Main) + +group(Main) using keys + +store(nfc) '0' +store(diaeresisBase) 'ae' + ++ 'a' > 'exay' + +c Test #1 for if() with context(n) + +if(nfc = "0") any(diaeresisBase) 'x' any(diaeresisBase) 'y' + 'b' > context(2) context(3) diff --git a/common/core/desktop/tests/unit/kmx/044 - if and context.kmx b/common/core/desktop/tests/unit/kmx/044 - if and context.kmx new file mode 100644 index 0000000000..7051334ee1 Binary files /dev/null and b/common/core/desktop/tests/unit/kmx/044 - if and context.kmx differ diff --git a/common/core/desktop/tests/unit/kmx/045 - deadkey and context.kmn b/common/core/desktop/tests/unit/kmx/045 - deadkey and context.kmn new file mode 100644 index 0000000000..09d2767828 --- /dev/null +++ b/common/core/desktop/tests/unit/kmx/045 - deadkey and context.kmn @@ -0,0 +1,17 @@ +c Description: Tests that context emits deadkeys correctly. See #4275. +c keys: [K_Y][K_Z][SHIFT K_SLASH] +c expected: correct +c context: + +store(&version) '10.0' + +begin Unicode > use(Main) + +group(Main) using keys + ++ 'y' > dk(1) 'a' dk(2) 'b' dk(3) + +c Test #2 for dk(d) and context + +dk(1) 'a' dk(2) 'b' dk(3) + 'z' > '<' context '>' +'<' dk(1) 'a' dk(2) 'b' dk(3) '>' + '?' > 'correct' diff --git a/common/core/desktop/tests/unit/kmx/045 - deadkey and context.kmx b/common/core/desktop/tests/unit/kmx/045 - deadkey and context.kmx new file mode 100644 index 0000000000..28421edfc9 Binary files /dev/null and b/common/core/desktop/tests/unit/kmx/045 - deadkey and context.kmx differ diff --git a/common/core/desktop/tests/unit/kmx/046 - deadkey and contextex.kmn b/common/core/desktop/tests/unit/kmx/046 - deadkey and contextex.kmn new file mode 100644 index 0000000000..390e01df2d --- /dev/null +++ b/common/core/desktop/tests/unit/kmx/046 - deadkey and contextex.kmn @@ -0,0 +1,17 @@ +c Description: Tests that context() emits deadkeys correctly. See #4275. +c keys: [K_Y][SHIFT K_M][SHIFT K_SLASH] +c expected: correct +c context: + +store(&version) '10.0' + +begin Unicode > use(Main) + +group(Main) using keys + ++ 'y' > dk(1) 'a' dk(2) 'b' dk(3) + +c Test #3 for dk(d) and context(n) + +dk(1) 'a' dk(2) 'b' dk(3) + 'M' > '<' context(1) '>' +'<' dk(1) '>' + '?' > 'correct' diff --git a/common/core/desktop/tests/unit/kmx/046 - deadkey and contextex.kmx b/common/core/desktop/tests/unit/kmx/046 - deadkey and contextex.kmx new file mode 100644 index 0000000000..4fd17f8aec Binary files /dev/null and b/common/core/desktop/tests/unit/kmx/046 - deadkey and contextex.kmx differ diff --git a/common/core/desktop/tests/unit/kmx/meson.build b/common/core/desktop/tests/unit/kmx/meson.build index bf41ad3b16..2c57275b86 100644 --- a/common/core/desktop/tests/unit/kmx/meson.build +++ b/common/core/desktop/tests/unit/kmx/meson.build @@ -58,7 +58,11 @@ tests = [ '040 - long context', '041 - long context and deadkeys', '042 - long context and split deadkeys', - '043 - output and keystroke' + '043 - output and keystroke', + + '044 - if and context', + '045 - deadkey and context', + '046 - deadkey and contextex' ] if build_machine.system() == 'windows' diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index f2b5456bc6..1b2808c62d 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index 6cb2a43721..69d2c405c2 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "14.0.222", + "version": "14.0.227", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^14.0.222", - "@keymanapp/resources-gosh": "^14.0.222", + "@keymanapp/lexical-model-compiler": "^14.0.227", + "@keymanapp/resources-gosh": "^14.0.227", "@types/node": "^11.9.4", "chai": "^4.2.0", "mocha": "^5.2.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^14.0.222", - "@keymanapp/lexical-model-layer": "^14.0.222", - "@keymanapp/models-types": "^14.0.222", - "@keymanapp/web-environment": "^14.0.222", - "@keymanapp/web-utils": "^14.0.222", + "@keymanapp/keyboard-processor": "^14.0.227", + "@keymanapp/lexical-model-layer": "^14.0.227", + "@keymanapp/models-types": "^14.0.227", + "@keymanapp/web-environment": "^14.0.227", + "@keymanapp/web-utils": "^14.0.227", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index f876d96e8f..6ab03ccd73 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index 776f34c016..0c1cd325e1 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "14.0.222", + "version": "14.0.227", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^14.0.222", + "@keymanapp/resources-gosh": "^14.0.227", "chai": "^4.2.0", "mocha": "^5.2.0", "mocha-teamcity-reporter": "^3.0.0", @@ -31,9 +31,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^14.0.222", - "@keymanapp/web-environment": "^14.0.222", - "@keymanapp/web-utils": "^14.0.222", + "@keymanapp/models-types": "^14.0.227", + "@keymanapp/web-environment": "^14.0.227", + "@keymanapp/web-utils": "^14.0.227", "@types/node": "^11.9.4", "ts-node": "^8.0.2" } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index 1afe36946a..e195cf5f38 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index 05be8abed4..da0b517970 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "14.0.222", + "version": "14.0.227", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^14.0.222", - "@keymanapp/models-types": "^14.0.222", - "@keymanapp/web-environment": "^14.0.222", - "@keymanapp/web-utils": "^14.0.222" + "@keymanapp/keyboard-processor": "^14.0.227", + "@keymanapp/models-types": "^14.0.227", + "@keymanapp/web-environment": "^14.0.227", + "@keymanapp/web-utils": "^14.0.227" }, "devDependencies": { "typescript": "^3.8.3" diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index cbec745b3b..4f8127ed73 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index f72b9d3f5a..e36c6e26b6 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "14.0.222", + "version": "14.0.227", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^14.0.222", + "@keymanapp/web-environment": "^14.0.227", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index fb4e4e33ed..a16431b8eb 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index b7da5f1cb5..5daf103bba 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "14.0.222", + "version": "14.0.227", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^14.0.222", - "@keymanapp/web-environment": "^14.0.222", + "@keymanapp/resources-gosh": "^14.0.227", + "@keymanapp/web-environment": "^14.0.227", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index 492a323835..7f1c51f3af 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index 02c727cc6b..95bf638ff5 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "14.0.222", + "version": "14.0.227", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^14.0.222", - "@keymanapp/web-utils": "^14.0.222", + "@keymanapp/models-types": "^14.0.227", + "@keymanapp/web-utils": "^14.0.227", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^14.0.222" + "@keymanapp/models-wordbreakers": "^14.0.227" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index 3780e7d6d2..9e27d8ffa3 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index 0b78eaa00e..cc549e0025 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "14.0.222", + "version": "14.0.227", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index 11b5f229d1..55f9ba31ca 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index feed3fdf7a..17b3dcd5f3 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "14.0.222", + "version": "14.0.227", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^14.0.222", + "@keymanapp/models-types": "^14.0.227", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.2.0", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index 962e5af5c1..cfc81d289d 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index 4a4ad822b5..f362f1f7ae 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "14.0.222", + "version": "14.0.227", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^14.0.222", - "@keymanapp/resources-gosh": "^14.0.222", + "@keymanapp/models-types": "^14.0.227", + "@keymanapp/resources-gosh": "^14.0.227", "@types/node": "^10.17.21", "chai": "^4.2.0", "karma": "^4.2.0", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^14.0.222", - "@keymanapp/models-wordbreakers": "^14.0.222", - "@keymanapp/web-environment": "^14.0.222", - "@keymanapp/web-utils": "^14.0.222", + "@keymanapp/models-templates": "^14.0.227", + "@keymanapp/models-wordbreakers": "^14.0.227", + "@keymanapp/web-environment": "^14.0.227", + "@keymanapp/web-utils": "^14.0.227", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/crowdin.yml b/crowdin.yml index f062ad886e..9653b16179 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -50,11 +50,17 @@ files: dest: /windows/strings.xml translation: /windows/src/desktop/kmshell/locale/%locale%/%original_file_name% type: android + languages_mapping: + locale: + de: de - source: /windows/src/desktop/setup/locale/en/strings.xml dest: /windows/setup/strings.xml translation: /windows/src/desktop/setup/locale/%locale%/%original_file_name% type: android + languages_mapping: + locale: + de: de # iOS files diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index eafb5cf6a9..771aef21fa 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/developer/js/package.json b/developer/js/package.json index 4a6be624b1..8a356b76ac 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "14.0.222", + "version": "14.0.227", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^14.0.222", + "@keymanapp/models-types": "^14.0.227", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^14.0.222", - "@keymanapp/models-wordbreakers": "^14.0.222", + "@keymanapp/models-templates": "^14.0.227", + "@keymanapp/models-wordbreakers": "^14.0.227", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/de.lproj/ResourceInfoView.strings b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/de.lproj/ResourceInfoView.strings new file mode 100644 index 0000000000..e6af056038 --- /dev/null +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/de.lproj/ResourceInfoView.strings @@ -0,0 +1,2 @@ +/* Class = "UILabel"; text = "Scan this code to load this keyboard on another device"; ObjectID = "z2O-MT-IoV"; */ +"z2O-MT-IoV.text" = "Scannen Sie diesen Code, um diese Tastatur auf einem anderen Gerät zu laden"; diff --git a/ios/engine/KMEI/KeymanEngine/de.lproj/Localizable.strings b/ios/engine/KMEI/KeymanEngine/de.lproj/Localizable.strings new file mode 100644 index 0000000000..eef298d640 Binary files /dev/null and b/ios/engine/KMEI/KeymanEngine/de.lproj/Localizable.strings differ diff --git a/ios/engine/KMEI/KeymanEngine/de.lproj/Localizable.stringsdict b/ios/engine/KMEI/KeymanEngine/de.lproj/Localizable.stringsdict new file mode 100644 index 0000000000..c095cdccf4 --- /dev/null +++ b/ios/engine/KMEI/KeymanEngine/de.lproj/Localizable.stringsdict @@ -0,0 +1,118 @@ + + + + + menu-langsettings-lexical-model-count + + NSStringLocalizedFormatKey + %#@count@ + count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + u + one + %u Wörterbuch installiert + other + %u Wörterbücher installiert + + + notification-update-failed + + NSStringLocalizedFormatKey + %#@count@ + count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + u + one + %u Aktualisierung fehlgeschlagen + other + %u Aktualisierungen fehlgeschlagen + + + notification-update-success + + NSStringLocalizedFormatKey + %#@count@ + count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + u + one + %u Aktualisierung erfolgreich + other + %u Aktualisierungen erfolgreich + + + settings-keyboards-installed-count + + NSStringLocalizedFormatKey + %#@count@ + count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + u + one + %u Tastatur installiert + other + %u Tastaturen installiert + + + settings-languages-installed-count + + NSStringLocalizedFormatKey + %#@count@ + count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + u + one + %u Sprache installiert + other + %u Sprachen installiert + + + package-default-found-keyboards + + NSStringLocalizedFormatKey + %#@count@ + count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + u + one + %u Tastatur im Paket gefunden: + other + %u Tastaturen im Paket gefunden: + + + package-default-found-lexical-models + + NSStringLocalizedFormatKey + %#@count@ + count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + u + one + %u Wörterbuch im Paket gefunden: + other + %u Wörterbücher im Paket gefunden: + + + + diff --git a/ios/keyman/Keyman/Keyman/de.lproj/Localizable.strings b/ios/keyman/Keyman/Keyman/de.lproj/Localizable.strings new file mode 100644 index 0000000000..a4cd15691a Binary files /dev/null and b/ios/keyman/Keyman/Keyman/de.lproj/Localizable.strings differ diff --git a/lerna.json b/lerna.json index 930363b581..76433edfa7 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "lerna", "typescript" ], - "version": "14.0.222" + "version": "14.0.227" } diff --git a/linux/keyman-config/locale/de_DE.po b/linux/keyman-config/locale/de_DE.po new file mode 100644 index 0000000000..9763ce6ef3 --- /dev/null +++ b/linux/keyman-config/locale/de_DE.po @@ -0,0 +1,332 @@ +msgid "" +msgstr "" +"Project-Id-Version: keyman\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-19 19:17+0200\n" +"PO-Revision-Date: 2021-01-19 08:16\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: keyman\n" +"X-Crowdin-Project-ID: 386703\n" +"X-Crowdin-Language: de\n" +"X-Crowdin-File: /master/linux/keyman-config.pot\n" +"X-Crowdin-File-ID: 504\n" + +#: keyman_config/__init__.py:68 +msgid "Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting." +msgstr "Weder sentry-sdk noch raven sind verfügbar. Sentry-Fehlerberichte werden nicht aktiviert." + +#: keyman_config/downloadkeyboard.py:23 +msgid "Download Keyman keyboards" +msgstr "Keyman-Tastaturen herunterladen" + +#: keyman_config/downloadkeyboard.py:37 keyman_config/keyboard_details.py:49 +#: keyman_config/keyboard_details.py:340 keyman_config/view_installed.py:205 +msgid "_Close" +msgstr "_Schließen" + +#: keyman_config/install_kmp.py:99 +msgid "You do not have permissions to install the keyboard files to the shared area /usr/local/share/keyman" +msgstr "Sie haben keine Berechtigung, die Tastaturdateien in den gemeinsamen Bereich /usr/local/share/keyman zu installieren" + +#: keyman_config/install_kmp.py:103 +msgid "You do not have permissions to install the documentation to the shared documentation area /usr/local/share/doc/keyman" +msgstr "Sie haben keine Berechtigung, die Dokumentation in den gemeinsamen Dokumentationsbereich /usr/local/share/doc/keyman zu installieren" + +#: keyman_config/install_kmp.py:107 +msgid "You do not have permissions to install the font files to the shared font area /usr/local/share/fonts" +msgstr "Sie haben keine Berechtigung, die Schriftarten in den gemeinsamen Bereich /usr/local/share/fonts zu installieren" + +#: keyman_config/install_kmp.py:179 +#, python-brace-format +msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {package}" +msgstr "install_kmp.py: Fehler: Keine kmp.json oder kmp.inf in {package} gefunden" + +#: keyman_config/install_kmp.py:246 +#, python-brace-format +msgid "install_kmp.py: error: No kmp.json or kmp.inf found in {packageFile}" +msgstr "install_kmp.py: Fehler: Keine kmp.json oder kmp.inf in {packageFile} gefunden" + +#: keyman_config/install_window.py:54 +#, python-brace-format +msgid "Installing keyboard/package {keyboardid}" +msgstr "Installiere Tastatur/Paket {keyboardid}" + +#: keyman_config/install_window.py:72 keyman_config/install_window.py:93 +msgid "Keyboard is installed already" +msgstr "Tastatur ist bereits installiert" + +#: 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 "Die {name} -Tastatur ist bereits in Version {version} installiert. Möchten Sie sie deinstallieren und dann neu installieren?" + +#: keyman_config/install_window.py:95 +#, python-brace-format +msgid "The {name} keyboard is already installed with a newer version {installedversion}. Do you want to uninstall it and install the older version {version}?" +msgstr "Die {name} -Tastatur ist bereits mit einer neueren Version {installedversion} installiert. Möchten Sie sie deinstallieren und dann die ältere Version {version} installieren?" + +#: keyman_config/install_window.py:128 +msgid "Keyboard layouts: " +msgstr "Tastatur-Layouts: " + +#: keyman_config/install_window.py:147 +msgid "Fonts: " +msgstr "Schriftarten: " + +#: keyman_config/install_window.py:167 keyman_config/keyboard_details.py:96 +msgid "Package version: " +msgstr "Paketversion: " + +#: keyman_config/install_window.py:179 +msgid "Author: " +msgstr "Autor: " + +#: keyman_config/install_window.py:197 +msgid "Website: " +msgstr "Webseite: " + +#: keyman_config/install_window.py:211 +msgid "Copyright: " +msgstr "Copyright: " + +#: keyman_config/install_window.py:245 +msgid "Details" +msgstr "Details" + +#: keyman_config/install_window.py:248 +msgid "README" +msgstr "LIESMICH" + +#: keyman_config/install_window.py:256 keyman_config/view_installed.py:200 +msgid "_Install" +msgstr "_Installieren" + +#: keyman_config/install_window.py:260 +msgid "_Cancel" +msgstr "_Abbrechen" + +#: keyman_config/install_window.py:305 +#, python-brace-format +msgid "Keyboard {name} installed" +msgstr "Tastatur {name} installiert" + +#: keyman_config/install_window.py:310 keyman_config/install_window.py:315 +#, python-brace-format +msgid "Keyboard {name} could not be installed." +msgstr "Tastatur {name} konnte nicht installiert werden." + +#: keyman_config/install_window.py:311 +msgid "Error Message:" +msgstr "Fehlermeldung:" + +#: keyman_config/install_window.py:316 +msgid "Warning Message:" +msgstr "Warnmeldung:" + +#: keyman_config/keyboard_details.py:37 +#, python-brace-format +msgid "{name} keyboard" +msgstr "{name}-Tastatur" + +#: keyman_config/keyboard_details.py:53 +msgid "ERROR: Keyboard metadata is damaged.\n" +"Please \"Uninstall\" and then \"Install\" the keyboard." +msgstr "FEHLER: Die Tastatur-Metadaten sind beschädigt.\n" +"Bitte \"deinstallieren\" Sie die Tastatur und \"Installieren\" dann erneut." + +#: keyman_config/keyboard_details.py:74 +msgid "Package name: " +msgstr "Paketname: " + +#: keyman_config/keyboard_details.py:85 +msgid "Package id: " +msgstr "Paket-Id: " + +#: keyman_config/keyboard_details.py:108 +msgid "Package description: " +msgstr "Paketbeschreibung: " + +#: keyman_config/keyboard_details.py:121 +msgid "Package author: " +msgstr "Paketautor: " + +#: keyman_config/keyboard_details.py:133 +msgid "Package copyright: " +msgstr "Copyright des Pakets: " + +#: keyman_config/keyboard_details.py:174 +msgid "Keyboard filename: " +msgstr "Tastatur-Dateiname: " + +#: keyman_config/keyboard_details.py:187 +msgid "Keyboard name: " +msgstr "Name der Tastatur: " + +#: keyman_config/keyboard_details.py:198 +msgid "Keyboard id: " +msgstr "Tastatur-Id: " + +#: keyman_config/keyboard_details.py:209 +msgid "Keyboard version: " +msgstr "Tastaturversion: " + +#: keyman_config/keyboard_details.py:221 +msgid "Keyboard author: " +msgstr "Tastatur-Autor: " + +#: keyman_config/keyboard_details.py:232 +msgid "Keyboard license: " +msgstr "Tastatur-Lizenz: " + +#: keyman_config/keyboard_details.py:243 +msgid "Keyboard description: " +msgstr "Tastaturbeschreibung: " + +#: keyman_config/keyboard_details.py:334 +#, python-brace-format +msgid "Scan this code to load this keyboard\n" +"on another device or share online" +msgstr "Scannen Sie diesen Code, um diese Tastatur\n" +"auf einem anderen Gerät zu laden oder online zu teilen" + +#: keyman_config/options.py:24 +#, python-brace-format +msgid "{packageId} Settings" +msgstr "{packageId} Einstellungen" + +#: keyman_config/view_installed.py:30 +msgid "Keyman Configuration" +msgstr "Keyman-Einstellungen" + +#: keyman_config/view_installed.py:60 +msgid "Choose a kmp file..." +msgstr "KMP-Datei auswählen..." + +#. i18n: file type in file selection dialog +#: keyman_config/view_installed.py:65 +msgid "KMP files" +msgstr "KMP-Dateien" + +#. i18n: column header in table displaying installed keyboards +#: keyman_config/view_installed.py:141 +msgid "Icon" +msgstr "Icon" + +#. i18n: column header in table displaying installed keyboards +#: keyman_config/view_installed.py:145 +msgid "Name" +msgstr "Name" + +#. i18n: column header in table displaying installed keyboards +#: keyman_config/view_installed.py:148 +msgid "Version" +msgstr "Version" + +#: keyman_config/view_installed.py:161 +msgid "_Uninstall" +msgstr "_Deinstallieren" + +#: keyman_config/view_installed.py:162 keyman_config/view_installed.py:304 +msgid "Uninstall keyboard" +msgstr "Tastatur deinstallieren" + +#: keyman_config/view_installed.py:167 +msgid "_About" +msgstr "_Über" + +#: keyman_config/view_installed.py:168 keyman_config/view_installed.py:306 +msgid "About keyboard" +msgstr "Über die Tastatur" + +#: keyman_config/view_installed.py:173 +msgid "_Help" +msgstr "_Hilfe" + +#: keyman_config/view_installed.py:174 keyman_config/view_installed.py:305 +msgid "Help for keyboard" +msgstr "Hilfe zur Tastatur" + +#: keyman_config/view_installed.py:179 +msgid "_Options" +msgstr "_Optionen" + +#: keyman_config/view_installed.py:180 keyman_config/view_installed.py:307 +msgid "Settings for keyboard" +msgstr "Einstellungen für Tastatur" + +#: keyman_config/view_installed.py:190 +msgid "_Refresh" +msgstr "_Aktualisieren" + +#: keyman_config/view_installed.py:191 +msgid "Refresh keyboard list" +msgstr "Tastaturliste aktualisieren" + +#: keyman_config/view_installed.py:195 +msgid "_Download" +msgstr "_Download" + +#: keyman_config/view_installed.py:196 +msgid "Download and install a keyboard from the Keyman website" +msgstr "Laden und installieren Sie eine Tastatur von der Keyman-Website" + +#: keyman_config/view_installed.py:201 +msgid "Install a keyboard from a file" +msgstr "Tastatur aus einer Datei installieren" + +#: keyman_config/view_installed.py:206 +msgid "Close window" +msgstr "Fenster schließen" + +#: keyman_config/view_installed.py:278 +#, python-brace-format +msgid "Uninstall keyboard {package}" +msgstr "Tastatur {package} deinstallieren" + +#: keyman_config/view_installed.py:280 +#, python-brace-format +msgid "Help for keyboard {package}" +msgstr "Hilfe zur Tastatur {package}" + +#: keyman_config/view_installed.py:282 +#, python-brace-format +msgid "About keyboard {package}" +msgstr "Über die Tastatur {package}" + +#: keyman_config/view_installed.py:284 +#, python-brace-format +msgid "Settings for keyboard {package}" +msgstr "Einstellungen für Tastatur {package}" + +#: keyman_config/view_installed.py:349 +msgid "Uninstall keyboard package?" +msgstr "Tastaturpaket deinstallieren?" + +#: keyman_config/view_installed.py:351 +#, python-brace-format +msgid "Are you sure that you want to uninstall the {keyboard} keyboard and its fonts?" +msgstr "Sind Sie sicher, dass Sie die {keyboard} -Tastatur und zugehörige Schriftarten deinstallieren möchten?" + +#: keyman_config/welcome.py:22 +#, python-brace-format +msgid "{name} installed" +msgstr "{name} installiert" + +#: keyman_config/welcome.py:40 +msgid "Open in _Web browser" +msgstr "Im _Web-Browser öffnen" + +#: keyman_config/welcome.py:42 +msgid "Open in the default web browser to do things like printing" +msgstr "Im Standard-Browser öffnen, z.B. um zu Drucken" + +#: keyman_config/welcome.py:45 +msgid "_OK" +msgstr "_OK" + diff --git a/linux/scripts/debian.sh b/linux/scripts/debian.sh index 511511306e..98546d4886 100755 --- a/linux/scripts/debian.sh +++ b/linux/scripts/debian.sh @@ -29,6 +29,7 @@ for proj in ${projects}; do downloadSource debianpackage cd ${proj}-${version} + dch -v ${version}-1 "Re-release to Debian" debuild -d -S -sa -Zxz cd ${BASEDIR} done diff --git a/linux/scripts/package-build.inc.sh b/linux/scripts/package-build.inc.sh index 01d368a520..11431385fb 100644 --- a/linux/scripts/package-build.inc.sh +++ b/linux/scripts/package-build.inc.sh @@ -39,8 +39,8 @@ function downloadSource() { make clean fi - # Update tier in Debian watch files (replacing any previously set tier) - sed "s/\$tier\|alpha\|beta\|stable/${TIER}/g" $BASEDIR/scripts/watch.in > debian/watch + # Update tier in Debian watch files (replacing any previously set tier) and remove comment + sed -e "s/\$tier\|alpha\|beta\|stable/${TIER}/g" -e "s/^# .*$//" $BASEDIR/scripts/watch.in > debian/watch version=$(uscan --report --dehs|xmllint --xpath "//dehs/upstream-version/text()" -) dirversion=$(uscan --report --dehs|xmllint --xpath "//dehs/upstream-url/text()" - | cut -d/ -f6) diff --git a/linux/scripts/watch.in b/linux/scripts/watch.in index 671684f430..d9d38cd3b5 100644 --- a/linux/scripts/watch.in +++ b/linux/scripts/watch.in @@ -1,3 +1,3 @@ version=4 -# Tier set by launchpad.sh script +# Tier replaced by package-build.inc.sh script https://downloads.keyman.com/linux/$tier/@ANY_VERSION@/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/SystemKeyboard.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/SystemKeyboard.java index f811a9f4f6..52ff694a46 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/SystemKeyboard.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/SystemKeyboard.java @@ -11,11 +11,13 @@ import android.view.Display; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; +import android.widget.FrameLayout; import com.tavultesoft.kmea.KMHardwareKeyboardInterpreter; import com.tavultesoft.kmea.KMManager; @@ -162,6 +164,16 @@ public class SystemKeyboard extends InputMethodService implements KeyboardEventH KMManager.onConfigurationChanged(newConfig); } + @Override + public void onConfigureWindow(Window win, boolean isFullscreen, boolean isCandidatesOnly) { + super.onConfigureWindow(win, isFullscreen, isCandidatesOnly); + + // We don't currently use isFullscreen or isCandidatesOnly; we always want to MATCH_PARENT, + // unlike the default for height which is WRAP_CONTENT. We then adjust the touchable area + // in `onCalculateInsets` + win.setLayout(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + } + @Override public void onComputeInsets(Insets outInsets) { super.onComputeInsets(outInsets); @@ -182,6 +194,7 @@ public class SystemKeyboard extends InputMethodService implements KeyboardEventH int bannerHeight = KMManager.getBannerHeight(this); int kbHeight = KMManager.getKeyboardHeight(this); outInsets.contentTopInsets = inputViewHeight - bannerHeight - kbHeight; + outInsets.visibleTopInsets = outInsets.contentTopInsets; outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_REGION; outInsets.touchableRegion.set(0, outInsets.contentTopInsets, size.x, size.y); } diff --git a/resources/build/l10n/README.md b/resources/build/l10n/README.md index 0a89c334a5..318e6815e3 100644 --- a/resources/build/l10n/README.md +++ b/resources/build/l10n/README.md @@ -1,6 +1,6 @@ # Localization Maintenance -Localization for Keyman is maintained at https://crowdin.com/project/keyman +Localization for Keyman is maintained at https://translate.keyman.com Downloading and updating files between Keyman and Crowdin happens automatically on GitHub by way of the Crowdin git integration. The configuration file for all platforms @@ -69,6 +69,9 @@ To download latest translations for the specific language: crowdin download -b master -l {language_code} ``` +Note: the Crowdin API doesn't handle custom languages so those will need to be manually synced. +See https://support.crowdin.com/api/language-codes/ + To display a list of latest translations from Crowdin: ```bash @@ -83,6 +86,12 @@ To upload source files to Crowdin: crowdin upload sources ``` +### Updating DisplayLanguages.java in Keyman Engine for Android +In Keyman for Android, the settings menu for changing display languages is maintained in +android/KMEA/app/src/main/java/com/tavultesoft/kmea/DisplayLangugages.java + +For the BCP-47 language tags to use in that file, don't include script names since the Android locales only handle language ID and region. + ## Tip Microsoft offers a website that allows to check how terms used in Windows are translated diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index 808c9abce3..6b4d7a654d 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index 0bffafa338..da519a7adb 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "14.0.222", + "version": "14.0.227", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/shellHelperFunctions.sh b/resources/shellHelperFunctions.sh index 64d80cb888..5d78bed831 100755 --- a/resources/shellHelperFunctions.sh +++ b/resources/shellHelperFunctions.sh @@ -251,13 +251,20 @@ set_version ( ) { # set_npm_version VERSION_WITH_TIER # set_npm_version () { + if [ $# == 0 ]; then + fail "set_npm_version requires a specified version." + fi + local version=$1 # We use --no-git-tag-version because our CI system controls version numbering and # already tags releases. We also want to have the version of this match the # release of Keyman Developer -- these two versions should be in sync. Because this # is a large repo with multiple projects and build systems, it's better for us that # individual build systems don't take too much ownership of git tagging. :) - npm --no-git-tag-version --allow-same-version version "$version" || fail "Could not set package version to $version." + pushd . > /dev/null + cd "${KEYMAN_ROOT}" + npm run version "$version" || fail "Could not set package versions to $version." + popd > /dev/null } # Initializes use of the npm `lerna` package within the repo. diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index 088e6c8374..fe7af7e80d 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index 8e287d5b13..394b31de24 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "14.0.222", + "version": "14.0.227", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^14.0.222" + "@keymanapp/resources-gosh": "^14.0.227" } } diff --git a/web/package-lock.json b/web/package-lock.json index 044119ad59..4bac3b2f32 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "14.0.222", + "version": "14.0.227", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/web/package.json b/web/package.json index a1032eef9b..36483af865 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "14.0.222", + "version": "14.0.227", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^14.0.222", - "@keymanapp/web-sentry-manager": "^14.0.222", + "@keymanapp/resources-gosh": "^14.0.227", + "@keymanapp/web-sentry-manager": "^14.0.227", "@sentry/cli": "^1.52.3", "chai": "^4.2.0", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^14.0.222", - "@keymanapp/keyboard-processor": "^14.0.222", - "@keymanapp/lexical-model-layer": "^14.0.222", - "@keymanapp/models-types": "^14.0.222", - "@keymanapp/recorder-core": "^14.0.222", - "@keymanapp/web-environment": "^14.0.222", - "@keymanapp/web-utils": "^14.0.222", + "@keymanapp/input-processor": "^14.0.227", + "@keymanapp/keyboard-processor": "^14.0.227", + "@keymanapp/lexical-model-layer": "^14.0.227", + "@keymanapp/models-types": "^14.0.227", + "@keymanapp/recorder-core": "^14.0.227", + "@keymanapp/web-environment": "^14.0.227", + "@keymanapp/web-utils": "^14.0.227", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0", diff --git a/web/samples/minified.html b/web/samples/minified.html index 0f2ce657bc..47466451d9 100644 --- a/web/samples/minified.html +++ b/web/samples/minified.html @@ -40,7 +40,9 @@ kmw.init({ attachType:'auto', resources:'' - }); + }).then(function() { + loadKeyboards(); + }); @@ -49,7 +51,7 @@ - +

KeymanWeb Sample Page - Fully Compiled/Minified Source

diff --git a/web/samples/multilingual.html b/web/samples/multilingual.html index acb453d0ad..d4646c5357 100644 --- a/web/samples/multilingual.html +++ b/web/samples/multilingual.html @@ -32,7 +32,9 @@ kmw.init({ attachType:'auto', resources:'' - }); + }).then(function() { + loadKeyboards(); + }); - +

KeymanWeb Multilingual Page Example

diff --git a/web/samples/unminified.html b/web/samples/unminified.html index f2b8b69c3a..ca24b402af 100644 --- a/web/samples/unminified.html +++ b/web/samples/unminified.html @@ -39,7 +39,9 @@ var kmw=window.keyman; kmw.init({ attachType:'auto' - }); + }).then(function() { + loadKeyboards(); + }); @@ -48,7 +50,7 @@ - +

KeymanWeb Sample Page - Unminified Source

diff --git a/web/source/dom/uiTouchHandlerBase.ts b/web/source/dom/uiTouchHandlerBase.ts index 78a0e82b10..ed3ac7aaa8 100644 --- a/web/source/dom/uiTouchHandlerBase.ts +++ b/web/source/dom/uiTouchHandlerBase.ts @@ -425,7 +425,11 @@ namespace com.keyman.dom { // Cancel touch if moved up and off keyboard, unless popup keys visible } else { let base = this.baseElement; - let top = (base.offsetParent as HTMLElement).offsetTop + base.offsetTop; + let parent = base.parentElement; // parentElement is _Box + let top = base.offsetTop; + if(parent) { + top += parent.offsetTop; + } let height = base.offsetHeight; let yMin = Math.max(5, top - 0.25 * height); let yMax = (top + height) + 0.25 * height; @@ -454,4 +458,4 @@ namespace com.keyman.dom { } } } -} \ No newline at end of file +} diff --git a/web/source/kmwuibutton.ts b/web/source/kmwuibutton.ts index aeab80fe38..b395203dc7 100644 --- a/web/source/kmwuibutton.ts +++ b/web/source/kmwuibutton.ts @@ -363,7 +363,7 @@ if(!window['keyman']['ui']['name']) { var _li1 = util['createElement']('li'); _li1.id = 'KMW_ButtonUI_KbdList'; var _a1 = util['createElement']('a'); - _a1.appendChild(document.createTextNode('English')); + _a1.appendChild(document.createTextNode('(System keyboard)')); _a1.onclick = ui._SelectKeyboard; _a1.href = '#'; diff --git a/web/source/kmwuifloat.ts b/web/source/kmwuifloat.ts index f5abea7ab1..c98a89cc8a 100644 --- a/web/source/kmwuifloat.ts +++ b/web/source/kmwuifloat.ts @@ -126,7 +126,7 @@ if(!window['keyman']['ui']['name']) { ui.innerDiv.appendChild(ui.KeyboardSelector); //this may need to be moved up.... // Check required interface alignment and default keyboard - var opt=util['getOption']('ui'),dfltKeyboard='English'; + var opt=util['getOption']('ui'),dfltKeyboard='(System keyboard)'; if(opt && typeof(opt) == 'object') { if(typeof(opt['position']) == 'string' && opt['position'] == 'right') @@ -237,7 +237,7 @@ if(!window['keyman']['ui']['name']) { */ ui.updateMenu = function(kbd,lg) { - var i=0,value='English'; + var i=0; // This can be called during startup before fully initialized - ignore if so if(!ui.initialized) return; diff --git a/web/source/kmwuitoggle.ts b/web/source/kmwuitoggle.ts index 49214e299e..68a627dd0a 100644 --- a/web/source/kmwuitoggle.ts +++ b/web/source/kmwuitoggle.ts @@ -696,7 +696,7 @@ if(!window['keyman']['ui']['name']) { var _li=util['createElement']('li'); var _a=util['createElement']('a'); - _a.innerHTML='English'; + _a.innerHTML='(System keyboard)'; _a.href="#"; _a.onclick = function() { return ui.selectKbd(-1); }; _a.id='KMWSel_$'; diff --git a/web/source/osk/oskManager.ts b/web/source/osk/oskManager.ts index 23b714f632..d0a2d98754 100644 --- a/web/source/osk/oskManager.ts +++ b/web/source/osk/oskManager.ts @@ -38,14 +38,17 @@ namespace com.keyman.osk { // OSK positioning fields userPositioned: boolean = false; - width: number; - height: number; x: number; y: number; noDrag: boolean = false; dfltX: string; dfltY: string; + // Fields used to store target OSK size when no keyboard has been loaded + // If a keyboard has been loaded, the VisualKeyboard values override these. + _baseWidth: number; + _baseHeight: number; + // OSK resizing-event state fields resizing: boolean; _VMoveX: number; @@ -282,6 +285,22 @@ namespace com.keyman.osk { } } + private get width(): number { + if(this.vkbd) { + return this.vkbd.width; + } else { + return this._baseWidth; + } + } + + private get height(): number { + if(this.vkbd) { + return this.vkbd.height; + } else { + return this._baseHeight; + } + } + /** * Function _GenerateVisualKeyboard * Scope Private @@ -587,8 +606,7 @@ namespace com.keyman.osk { } var r=this.getRect(); - this.width = r.width; - this.height = r.height; + this.setSize(r.width, r.height, true); e.cancelBubble = true; return false; }.bind(this); @@ -791,8 +809,7 @@ namespace com.keyman.osk { } var r=this.getRect(); - this.width=r.width; - this.height=r.height; + this.setSize(r.width, r.height, true); this.x = r.left; this.y = r.top; e.cancelBubble = true; @@ -871,14 +888,10 @@ namespace com.keyman.osk { * * @return {boolean} */ - loadCookie() { + loadCookie(): void { let util = com.keyman.singleton.util; var c = util.loadCookie('KeymanWeb_OnScreenKeyboard'); - if(typeof(c) == 'undefined' || c == null) { - this.userPositioned=false; - return false; - } this._Enabled = util.toNumber(c['visible'], 1) == 1; this.userPositioned = util.toNumber(c['userSet'], 0) == 1; @@ -924,43 +937,19 @@ namespace com.keyman.osk { if(this.userPositioned && this._Box) { this.setPos({'left': this.x, 'top': this.y}); } - - return true; } - private setSize(width?: number, height?: number) { + private setSize(width?: number, height?: number, pending?: boolean) { if(width && height) { - this.width = width; - this.height = height; + this._baseWidth = width; + this._baseHeight = height; } if(this.vkbd) { - this.vkbd.kbdDiv.style.width=this.width+'px'; - this.vkbd.kbdDiv.style.height=this.height+'px'; - this.vkbd.kbdDiv.style.fontSize=(this.height/8)+'px'; + this.vkbd.setSize(width, height, pending); } } - getWidthFromCookie(): number { - let util = com.keyman.singleton.util; - - var c = util.loadCookie('KeymanWeb_OnScreenKeyboard'); - if(typeof(c) == 'undefined' || c == null) { - return screen.width * 0.3; - } - - // Restore OSK size - font size now fixed in relation to OSK height, unless overridden (in em) by keyboard - var newWidth=util.toNumber(c['width'], 0.3 * screen.width); // Default - 30% of screen's width. - - if(newWidth < 0.2*screen.width) { - newWidth = 0.2*screen.width; - } else if(newWidth > 0.9*screen.width) { - newWidth=0.9*screen.width; - } - - return newWidth; - } - /** * Get the wanted height of the banner (does not include the keyboard) * @return {number} height in pixels @@ -1125,7 +1114,7 @@ namespace com.keyman.osk { w=0.9*screen.width; } ds.width=w+'px'; - this.width=w; + this.setSize(w, this.height, true); } // Set height, but limit to reasonable value @@ -1141,7 +1130,7 @@ namespace com.keyman.osk { h=0.5*screen.height; } ds.height=h+'px'; ds.fontSize=(h/8)+'px'; - this.height=h; + this.setSize(this.width, h, true); } // Fix or release user resizing @@ -1318,9 +1307,8 @@ namespace com.keyman.osk { } this._Enabled=true; this._Visible=true; - if(this.vkbd && this.vkbd.kbdDiv) { - this.width=this.vkbd.kbdDiv.offsetWidth; - this.height=this.vkbd.kbdDiv.offsetHeight; + if(this.vkbd) { + this.vkbd.refit(); } this.saveCookie(); @@ -1365,9 +1353,8 @@ namespace com.keyman.osk { } // Save current size if visible - if(this._Box && this._Box.style.display == 'block' && this.vkbd && this.vkbd.kbdDiv) { - this.width = this.vkbd.kbdDiv.offsetWidth; - this.height = this.vkbd.kbdDiv.offsetHeight; + if(this._Box && this._Box.style.display == 'block' && this.vkbd) { + this.vkbd.refit(); } if(hiddenByUser) { @@ -1546,4 +1533,4 @@ namespace com.keyman.osk { } } } -} \ No newline at end of file +} diff --git a/web/source/osk/visualKeyboard.ts b/web/source/osk/visualKeyboard.ts index 67d376885b..939dcd6065 100644 --- a/web/source/osk/visualKeyboard.ts +++ b/web/source/osk/visualKeyboard.ts @@ -133,7 +133,7 @@ namespace com.keyman.osk { let metrics = OSKKey.getTextMetrics(osk, this.spec.text, style); let fontSpec = util.getFontSizeStyle(style.fontSize); - let keyWidth = this.getKeyWidth(); + let keyWidth = this.getKeyWidth(osk); const MAX_X_PROPORTION = 0.90; const MAX_Y_PROPORTION = 0.90; const X_PADDING = 2; @@ -169,7 +169,7 @@ namespace com.keyman.osk { } } - getKeyWidth(): number { + getKeyWidth(osk: VisualKeyboard): number { let units = this.objectUnits(); if(units == 'px') { @@ -178,12 +178,9 @@ namespace com.keyman.osk { } else if(units == '%') { // For desktop devices, each key is given a %age of the total OSK width. We'll need to compute an // approximation for that. `this.kbdDiv` is the element controlling the OSK's width, set in px. - // ... and since it's null whenever this method would be called during key construction, we simply - // grab it from the cookie (or its default values) instead. - let oskWidth = com.keyman.singleton.osk.getWidthFromCookie(); // This is an approximation that tends to be a bit too large, but it's close enough to be useful. - return Math.floor(oskWidth * this.spec['widthpc'] / 100); + return Math.floor(osk.width * this.spec['widthpc'] / 100); } } @@ -608,6 +605,9 @@ namespace com.keyman.osk { kbdHelpDiv: HTMLDivElement; styleSheet: HTMLStyleElement; + _width: number; + _height: number; + // Style-related properties fontFamily: string; fontSize: string; @@ -709,6 +709,84 @@ namespace com.keyman.osk { } } + get width(): number { + if(this._width) { + return this._width; + } else { + this.loadSizeFromCookie(); + return this.width; + } + } + + get height(): number { + if(this._height) { + return this._height; + } else { + this.loadSizeFromCookie(); + return this.height; + } + } + + protected loadSizeFromCookie() { + let keyman = com.keyman.singleton; + let util = keyman.util; + + // If no prior cookie exists, it merely returns an empty object / cookie. + var c = util.loadCookie('KeymanWeb_OnScreenKeyboard'); + var newWidth: number, newHeight: number; + + // Restore OSK size - font size now fixed in relation to OSK height, unless overridden (in em) by keyboard + newWidth=util.toNumber(c['width'], 0.333 * screen.width); // Default - 1/3rd of screen's width. + + if(newWidth < 0.2*screen.width) { + newWidth = 0.2*screen.width; + } else if(newWidth > 0.9*screen.width) { + newWidth=0.9*screen.width; + } + + // Default height decision made here: + // https://github.com/keymanapp/keyman/pull/4279#discussion_r560453929 + newHeight=util.toNumber(c['height'], 0.333 * newWidth); + + if(newHeight < 0.15*screen.height) { + newHeight = 0.15 * screen.height; + } else if(newHeight > 0.5*screen.height) { + newHeight=0.5*screen.height; + } + + this.setSize(newWidth, newHeight); + } + + /** + * Sets & tracks the size of the VisualKeyboard's primary element. + * @param width + * @param height + * @param pending Set to `true` if called during a resizing interaction + */ + public setSize(width: number, height: number, pending?: boolean) { + this._width = width; + this._height = height; + + if(!pending && this.kbdDiv) { + this.kbdDiv.style.width=this._width+'px'; + this.kbdDiv.style.height=this._height+'px'; + this.kbdDiv.style.fontSize=(this._height/8)+'px'; + } + } + + public defaultFontSize(): number { + return this.height / 8; + } + + /** + * Called by OSKManager after resize operations in order to determine the final + * size actually used by the visual keyboard. + */ + public refit() { + this._width=this.kbdDiv.offsetWidth; + this._height=this.kbdDiv.offsetHeight; + } + /** * Returns the default properties for a key object, used to construct * both a base keyboard key and popup keys @@ -1238,7 +1316,8 @@ namespace com.keyman.osk { // Cancel touch if moved up and off keyboard, unless popup keys visible } else { // _Box has (most of) the useful client values. - let _Box = this.kbdDiv.offsetParent as HTMLElement; // == osk._Box + let keyman = com.keyman.singleton; + let _Box = this.kbdDiv.parentElement ? this.kbdDiv.parentElement : keyman.osk._Box; let height = (this.kbdDiv.firstChild as HTMLElement).offsetHeight; // firstChild == layer-group, has height info. // We need to adjust the offset properties by any offsets related to the active banner. @@ -1691,7 +1770,7 @@ namespace com.keyman.osk { } else if(keyman.getActiveLanguage(true)) { lgName=keyman.getActiveLanguage(true); } else { - lgName='English'; + lgName='(System keyboard)'; } try { @@ -1739,10 +1818,12 @@ namespace com.keyman.osk { if(usePreview) { // Previews are not permitted for keys using any of the following CSS styles. - var excludedClasses = ['kmw-key-shift', // special keys - 'kmw-key-shift-on', // active special keys (shift, when in shift layer - 'kmw-spacebar', // space - 'kmw-key-blank', // Keys that are only used for layout control + var excludedClasses = ['kmw-key-shift', // special keys + 'kmw-key-shift-on', // active special keys (shift, when in shift layer + 'kmw-key-special', // special keys that require the keyboard's OSK font + 'kmw-key-special-on', // active special keys requiring the keyboard's OSK font + 'kmw-spacebar', // space + 'kmw-key-blank', // Keys that are only used for layout control 'kmw-key-hidden']; for(let c=0; c < excludedClasses.length; c++) { @@ -1828,7 +1909,7 @@ namespace com.keyman.osk { let util = keyman.util; if(this.device.formFactor == 'desktop') { - let kbdFontSize = this.getFontSizeFromCookie(); + let kbdFontSize = this.defaultFontSize(); let keySquareScale = 0.8; // Set in kmwosk.css, is relative. return kbdFontSize * keySquareScale; } else { @@ -1852,23 +1933,6 @@ namespace com.keyman.osk { } } - getFontSizeFromCookie(): number { - let keyman = com.keyman.singleton; - let util = keyman.util; - - var c = util.loadCookie('KeymanWeb_OnScreenKeyboard'); - if(typeof(c) == 'undefined' || c == null) { - return 16; - } - - var newHeight=util.toNumber(c['height'],0.15*screen.height); - if(newHeight > 0.5*screen.height) { - newHeight=0.5*screen.height; - } - - return (newHeight/8); - } - /** * Set the reference to a special function key for the * currently visible OSK layer @@ -2629,14 +2693,14 @@ namespace com.keyman.osk { let keymanweb = com.keyman.singleton; let util = keymanweb.util; - if(typeof(kfd) == 'undefined' && typeof(ofd) == 'undefined') { - return true; - } + let fontDefined = !!(kfd && kfd['files']); + kfd = fontDefined ? kfd : undefined; - if(typeof(kfd['files']) == 'undefined' && typeof(ofd['files']) == 'undefined') { - return true; - } + let oskFontDefined = !!(ofd && ofd['files']); + ofd = oskFontDefined ? ofd : undefined; + // Automatically 'ready' if the descriptor is explicitly `undefined`. + // Thus, also covers the case where both are undefined. var kReady=util.checkFontDescriptor(kfd), oReady=util.checkFontDescriptor(ofd); if(kReady && oReady) { return true; diff --git a/web/testing/unminified - manual.html b/web/testing/unminified - manual.html index 89975ef118..09e39ca797 100644 --- a/web/testing/unminified - manual.html +++ b/web/testing/unminified - manual.html @@ -38,8 +38,10 @@ diff --git a/web/testing/unminified.html b/web/testing/unminified.html index f83b4ba2cb..0e850a8ce9 100644 --- a/web/testing/unminified.html +++ b/web/testing/unminified.html @@ -38,8 +38,10 @@ @@ -48,7 +50,7 @@ - +

KeymanWeb Sample Page - Unminified Source

diff --git a/windows/src/desktop/kmshell/locale/de/strings.xml b/windows/src/desktop/kmshell/locale/de/strings.xml index c831487c5f..bee8aa4ca4 100644 --- a/windows/src/desktop/kmshell/locale/de/strings.xml +++ b/windows/src/desktop/kmshell/locale/de/strings.xml @@ -1,309 +1,924 @@ - + + - Bildschirmtastatur schließen - &Verlassen - Wenn inaktiv, ausblenden - &Hilfe - Sie haben die Bildschirmtastatur geschlossen. Keyman Desktop läuft immer noch. Mit einem Klick auf „Bildschirmtastatur“ in dem Keyman Menü, darfen Sie die Bildschirmtastatur jederzeit wieder öffnen. - Sind Sie sicher, daß Sie Keyman verlassen wollen? Wenn Sie Ihre Standard-Tastatur benutzen möchten, müssen Sie Keyman nicht verlassen. Mit einem Klick auf „Keyman ausschalten“ in dem Keyman Menü, können Sie Ihre Standard-Tastatur benutzen. - Die Bildschirmtastatur wird geschlossen - Keyman Verlassen? - AltGR mit STRG+Alt simulieren - Die Bildschirmtastatur wird angezeigt, wenn eine Keyman Tastaturbelegung ausgewählt ist - Die am geeignetste Ansicht der Bildschirmtastatur wird automatisch gewählt, wenn eine Tastaturbelegung aktiviert wird - Der Keyman wird wöchentlich automatisch aktualisiert, wenn es Updates gibt - Fehlersuchen einschalten - Fortgeschritten - Üblich - Bildschirmtastatur - Start - Die Tastenkürzel schalten Tastaturbelegungen und Einstellungen ein UND aus - Umschalt/Strg/Alt/AltGr wird in die Bildschirmtastatur losgelassen, wenn eine Taste geklickt wird - Benutzer Berechtigungen werden immer in Windows Vista erhöht - Tipps aktivieren - Den Startbildschirm anzeigen - Der Willkommenschirm anzeigen - Mit Windows starten - Die Windows Tastaturbelegung wird getauscht, wenn eine Keyman Tastaturbelegung ausgewählt ist - Als Keyman startet, wird Windows auf widersprüchliche Anwendungen geprüft - Die Unicode ergänzender Zeichen-Display einschalten (Neustart erforderlich) - In Windows "unbekannte Sprache" einschalten - &Bildschirmtastatur - Hilfe öffnen - Keyman Konfiguration öffnen - Drucken... - Beta Version! - Abbrechen - Nach Updates suchen... - Schließen - Diagnostik - Tastaturbelegung herunterladen... - Tastaturbelegung installieren... - Einstellungen - OK - Tavultesoft Kundenbetreuung... - Tastaturbelegungspaket Einstellungen - Proxy-Einstellungen - Tips zurücksetzen - Sprache der Oberfläche... - Urheber: - - Urheberrecht: - Beschreibung: - Enkodierungen: - Dateinamen: - Schriften: - Erste Schritte - Hilfe - Anwendung für: - Tastaturbelegungen: - Art von Tastaturbelegung: - Meldungen: - Bildschirmtastatur: - Tastaturbelegungspaket: - Version: - Webseite: - Keyman Konfiguration - Nur herunterladen, nicht installieren - Tastaturbelegung von Tavultesoft herunterladen - Hilfe für - Tastaturbelegungshilfe - Hilfe - Erste Schritte - Keyman Hilfe - Die - Tastaturbelegung aktivieren - Die - Sprache aktivieren - keines - Keyman Konfiguration öffnen - Keyman Menü öffnen - Die Bildschirmtastatur zeigen - Keyman ausschalten - Tastenkürzel - K - alle Benutzer - aktueller Benutzer - Installieren - Für alle Benutzer installieren - Details - Lies mich - Tastaturbelegung(en) installieren - Tastaturbelegung - T - Keine Tastaturbelegungen sind installiert worden. Klicken Sie auf 'Tastaturbelegung herunterladen', um eine Tastaturbelegung von der Tavultesoft Website zu installieren. - Wollen Sie, daß diese Aufgaben jetzt vom Keyman Desktop fertiggestellt werden? - Keyman Desktop hat folgende Einstellungen gefunden, die vervollständigt werden sollen, um - Skript(e), um auf Ihrem Computer korrekt zu funktionieren - Weitere Informationen... - Sprach-Einstellungshinweise - Microsoft Office-Sprachunterstützung - Nicht erneut fragen - Sprache-Konfigurationsaufgaben - Konfigurieren Sie Ihren Computer für - - Installierte Sprache - Keyman Tastaturbelegung - (Windows-Tastaturbelegung benutzen) - Windows-Tastaturbelegung - Gedächtnishilfe (mnemotechnische Tastatur) - Feste Position (unveränderliche Tastatur) - Tastenkürzel verändern... - Die Spracheinstellungen (auf Kompabilität mit Keyman-Tastaturbelegungen) überprüfen - Diagnostik - Bildschirmtastatur installieren - Tastenkürzel setzen... - Tastaturbelegungshilfe - Deinstallieren - Bildschirmtastatur deinstallieren - Tastaturbelegungspaket deinstallieren - Nein - installierte - nicht installierte - Einstellungen - E - Paßwort: - Port: - Server: - Proxy-Server-Konfiguration - Benutzername: - Keyman - Keyman - Unterstützung - U - Copyright 1994-2009 Tavultesoft Pty Ltd. Alle Rechte vorbehalten. - Systemversion - Version - Abbrechen - Jetzt installieren - Komponenten-Updates - Dürfen Sie die neue Version herunterladen: - Möchten Sie jetzt die Webseite besuchen? - Möchten Sie jetzt den Patch herunterladen und installieren? - Es gibt Updates für Keyman - Wählen Sie die Updates, die Sie installieren möchten: - Alte Version - Größe - Keyman Komponenten-Updates Verfügbar - Keyman Konfiguration - %Name; Hilfe - Klicken Sie auf die Schaltflächen unten, um weitere Unterlagen oder die Bildschirmtastatur anzuzeigen. - Diese Tastaturbelegung hat keine Erste Schritte oder andere Hilfe. Bitte sehen Sie das Startmenü nach, oder wenden Sie Sich an den Entwickler der Tastaturbelegung, um weitere Informationen über die Verwendung dieser Tastaturbelegung zu bekommen. - Keine Tastaturbelegungen sind gegenwärtig in Keyman aktiviert. Klicken Sie auf eine der Icons im Toolbar oben, um eine Tastaturbelegung auszuwählen. - Keine Tastaturbelegungen sind zurzeit installiert oder geladen worden. Benutzen Sie Keyman Konfiguration, um eine Tastaturbelegung zu installieren. - Bildschirmtastatur - Erste Schritte - Tastaturbelegungshilfe - Ja - Als Webseite speichern... - Toolbar der Bildschirmtastatur anzeigen - Segoe UI - 9 - Wollen Sie $(SKShortApplicationTitle) jetzt online mit der Zulassungsnummer %0:s aktivieren? Wenn Sie auf Nein klicken, können Sie von alternativen Methoden aktivieren. - Ihre Lizenz wurde erfolgreich aktiviert. - Für Ihre Sprache(n) wird Microsoft Windows richtig konfiguriert. - Codepage - Keyman - Abbrechen - Tastenkürzel löschen - &Herunterladen - Hilfe - Nein - OK - &Ausdrucken... - Mehreren Sprachen online suchen... - Ja - Keyman Desktop konnte nicht gestartet werden. Bevor Sie fortfahren, überprüfen Sie bitte Ihre Sicherheitseinstellungen, um zu wissen, ob das Programm keyman.exe erlaubt wird. Der erhaltenen Fehler war: %0:s. Wollen Sie versuchen, Keyman Desktop nun wieder zu starten? - Tastenkürzel verändern - Die Hilfedatei $(SKOnlineHelpFile) wurde nicht gefunden. - Die Tastaturbelegung konnte nicht erfolgreich ausgedruckt werden. Bitte speichern Sie sie zu einer Website und manuell ausdrucken. - <Die Tastaturbelegung wird beschädigt> - Die Informationen des Keyman Fehlersuchens werden auf dem Desktop in eine Textdatei gespeichert werden, die keymanlog\system.log heißt. Bevor Sie die Textdatei öffnen oder löschen, sollen Sie Keyman verlassen. ACHTUNG: Die Textdatei kann sehr schnell groß wachsen. Wenn Fehlersuchen aktiviert ist, wird Ihr System langsamer sein. Aus diesem Grund, sollten Sie es nur auf Anraten von der Tavultesoft Kundenbetreuung benutzen. DATENSCHUTZ WARNUNG: Bitte beachten Sie, dass die Textdatei des Fehlersuchens alle Ihre Tastatureingaben speichert. Sie sollten diese Option nur anschalten während eines Fehlersuchens oder Diagnosetest, und die Textdatei loschen so bald wie möglich. - en - Sprache der Benutzerschnittstelle ändern - Herunterladen von Dateien - Aktiviert werden kann der Browser oder email-Programm für dieser URL nicht. - Alle Tips sind zurückgesetzt worden und werden wieder angezeigt werden. - Das Tastenkürzel %0:s steht im Widerspruch zu dem ausgewählten Tastenkürzel für die %1:s Tastaturbelegung. Wenn Sie forfahren wird das Tastenkürzel für Keyboard %1:s wird gelösch. Forfahren? - Sie können Tastaturbelegungen nur als Administrator installieren oder deinstallieren. Benutzen Sie Die Systemsteuerung, um Sprachen für einen normalen Benutzer auszuwählen. - Eine Tastaturbelegung mit dem Name '%0:s' wurde bereits installiert. Wenn Sie fortfahren würde, wird sie deinstalliert werden, bevor die neue Tastaturbelegung installiert wird. Fortfahren? - Die Tastaturbelegung '%0:s' ist von dem Tastaturbelegungspaket '%1:s'. Sie müssen die ganzen Tastaturbelegungspaket deinstallieren. Fortfahren? - %0:s Bearbeitungsunterstützung zu %1:s fügen. - Microsoft Office 2000 - Microsoft Office 2003 - Microsoft Office 2007 - Microsoft Office XP - Die Sprache %0:s installieren und mit der Keyman Tastaturbelegung %1:s verknüpfen - Die Sprache %0:s mit der Keyman Tastaturbelegung %1:s verknüpfen - deu - Keine Tastaturbelegungen werden installiert. Bitte öffnen Sie „Konfiguration“, um eine Tastaturbelegung für Ihre Sprache zu installieren. - KeymanDesktop.chm - Dieses Betriebssystem ist nicht unterstützt. Für weitere Informationen, wenden Sie Sich bitte an Tavultesoft. - Ein Tastaturbelegungspaket mit dem Name %0:s wurde bereits installiert. Möchten Sie es deinstallieren, um das neue Tastaturbelegungspaket zu installieren? - Diese(s) Tastaturbelegungspaket(spaket) '%0:s' hat keine Tastaturbelegungshilfe. - Es können nicht alle Tastaturen in diesem Packet installiert werden. Sie können maximal %0:d zusätzliche Tastaturen installieren. Bitte wählen Sie aus diesem Packet die Tastaturen, die Sie installieren möchten. - Wählen Sie Ihre Tastaturbelegungen - Tastenkürzel setzen - Das Tastenkürzel der %0:s Tastaturbelegung setzen - Das Tastenkürzel der %0:s Sprache setzen - Keyman - Version %0:s - Änderung der Surrogates Einstellungen erfordert ein Computer-Neustart. Möchten Sie Windows jetzt neu starten? - Wählen Sie die Sprache Ihrer Benutzerschnittstelle. - Deutsch - Deutsch (German) - Die Zeichentabelle hat eine Datenbank von Zeichen, die aufgebaut werden muss, bevor man sie benutzen kann. Jetzt aufbauen? - Die Unicode Zeichen-Datenbank konnte nicht aufgebaut werden und wurde deaktiviert. Der Fehler ist: %0:s - Die Unicode Zeichen-Datenbank konnte nicht gelöscht werden für einen Wiederaufbau. Der Fehler ist: %0:s - Die Unicode Zeichen-Datenbank wurde nicht erfolgreich geladen (%0:s). Jetzt wiederaufbauen? - Unicode - Sind Sie sicher, daß Sie die Tastaturbelegung %0:s deinstallieren wollen? - Sind Sie sicher, daß Sie die Bildschirmtastatur für %0:s deinstallieren wollen? - Sind Sie sicher, daß Sie das Tastaturbelegungspaket %0:s deinstallieren wollen? - Sie könnten die '%0:s' Tastaturbelegung deinstallieren, nur wenn Sie ein Administrator seien. - Das Tastenkürzel %0:s steht im Widerspruch zu den Standardtasten. Sie sollten zumindest STRG- oder ALT-Taste benutzen. Möchten dies nun ändern? - Keyman %0:s - Die %0:s Tastaturbelegung %1:s - Die Tavultesoft Webseite ist nicht erreichbar - bitte testen Sie Ihre Internet-Verbindung, und versuchen Sie es erneut. - Die Tavultesoft Webseite ist nicht erreichbar - bitte testen Sie Ihre Internet-Verbindung, und versuchen Sie es erneut. Der erhaltenen Fehler war: %0:s - Keyman ausschalten - Zeichentabelle anzeigen - Schrift-Helfer anzeigen - Tastaturbelegungshilfe anzeigen - Bildschirmtastatur anzeigen - Keyman - Apply - Remind me Later - Click this icon to select a keyboard - Keyman is still running. Click this icon to use your language keyboard at any time - Keep in Touch - T - Keyboard version: - Languages: - - Add language - Custom - Documentation: - Installed - Not installed - Keyboard options - Treat hardware deadkeys as plain keys - Select keyboard layout for all applications - Base Keyboard... - Show Keyboard Usage Pane - Show Font Helper Pane - Show Character Map Pane - Open Text Editor - Open Language Switcher - General Hotkeys - Keyboard Layouts - Upgrade now! - Send Support Request - Contact Keyman Support - If you have any issues using Keyman, just ask a question on the Keyman Community Forum. - Open Keyman Community Forum - Useful Links - Set Base Keyboard - Select the base Latin script -keyboard that you use in Windows. Keyman keyboards will adapt automatically to your preferred layout. - Keyman updates are available - Click this icon to download and install updates - View and &install Keyman updates - E&xit online update check - Keyman - Start Keyman - Exit - Other tasks - Configuration - Show this screen at startup - Hide this screen at startup - Display in - Find other display languages online... - Help translate the user interface... - Create a new translation online - Don't show this hint again - The following fonts will also be uninstalled: %0:s. - Microsoft Office 2010 - Please wait while Keyman finds the fonts that will work with - keyboard. - - is not a Unicode keyboard. Fonts cannot be automatically located. Please check the keyboard documentation for font information. - The following fonts work with - keyboard: - The following fonts may also work: - The following fonts may work with - keyboard: - No fonts were found on your system that work with - . Please check the documentation to find fonts for this keyboard. - No keyboard layouts are currently installed or loaded. Use Keyman Configuration to install a keyboard layout. - Please choose a Keyman keyboard to find the fonts that will work with it. - Hint: - Resize the On Screen Keyboard by clicking and dragging on the window border - Move the On Screen Keyboard by clicking and dragging on the "Keyman" title - Insert any Unicode character into your document with the - Character Map Tool - Find out which fonts will work with your language with the - Font Helper Tool - Get more help on the keyboard by clicking the - Keyboard Usage button + + + + Keyman + + + + Segoe UI + + + + 9 + + + + &Ja + + + + &Nein + + + + Ok + + + + Abbrechen + + + + Schließen + + + + Ok + + + + Abbrechen + + + + Klicken Sie auf dieses Symbol, um eine Tastatur auszuwählen + + + + Keyman läuft noch. Klicken Sie auf dieses Symbol, um die Tastatur für Ihre Sprache jederzeit zu verwenden + + + + Keyman-Einstellungen + + + + Hilfe + + + + Tastatur-Layouts + + + + T + + + + Einstellungen + + + + E + + + + Tastenkürzel + + + + K + + + + Support + + + + S + + + + In Kontakt bleiben + + + + I + + + + Dateinamen: + + + + Paketversion: + + + + Tastaturversion: + + + + Autor: + + + + Webseite: + + + + Paket: + + + + Schriftarten: + + + + Tastatur-Layouts: + + + + Tastaturbelegung: + + + + Tastatursprache: + + + + Kodierungen: + + + + Art von Tastatur: + + + + Feste Position (unveränderliche Tastatur) + + + + Mnemonisch (entsprechend der Windows-Tastatur) + + + + Sprachen: + + + + + + + + Sprache hinzufügen + + + + Bildschirmtastatur: + + + + Benutzerdefiniert + + + + Installiert + + + + Nicht installiert + + + + Dokumentation: + + + + Installiert + + + + Nicht installiert + + + + Meldungen: + + + + Copyright: + + + + Änderungen werden sofort vorgenommen + + + + Tastatur installieren... + + + + Tastatur herunterladen... + + + + Tastaturoptionen + + + + Es sind keine Tastaturen installiert. Klicken Sie auf \'Tastatur herunterladen\', um eine Tastatur von der Keyman-Website zu installieren. + + + + + Sie können die \'%0:s\'-Tastatur nur deinstallieren, wenn Sie ein Administrator sind + + + + Tastatur teilen + + + + Scannen Sie diesen Code, um diese Tastatur auf einem anderen Gerät zu laden oder + + + + online zu teilen + + + + + + + + Allgemein + + + + Start + + + + Bildschirmtastatur + + + + Erweitert + + + + Die Tastenkürzel schalten Tastaturen ein UND aus + + + + AltGr mit Strg+Alt simulieren + + + + Hardware-Deadkeys wie normale Tasten behandeln + + + + Hinweise aktivieren + + + + Fehler automatisch an keyman.com melden + + + + Anonyme Nutzungsstatistiken mit keyman.com teilen + + + + Mit Windows starten + + + + Den Startbildschirm anzeigen + + + + Willkommensbildschirm anzeigen + + + + keyman.com wöchentlich auf Updates überprüfen + + + + Beim Start von Keyman nach inkompatiblen Anwendungen suchen + + + + Umschalt/Strg/Alt auf der Bildschirmtastatur freigeben, nachdem eine Taste geklickt wurde + + + + Bildschirmtastatur immer anzeigen wenn eine Keyman-Tastatur ausgewählt ist + + + + Bildschirmtastatur bzw. Hilfe automatisch anzeigen, wenn eine Tastatur ausgewählt wird + + + + Die Unicode ergänzender Zeichen-Display einschalten (Neustart erforderlich) + + + + In Windows \"unbekannte Sprache\" einschalten + + + + Fehlersuchen einschalten + + + + Windows-Tastatur automatisch wechseln, wenn eine Keyman-Tastatur ausgewählt wird + + + + Tastaturlayout für alle Anwendungen auswählen + + + + Benutzer Berechtigungen werden immer in Windows Vista erhöht + + + + Basis-Tastatur... + + + + + + + + + + + + + (keine) + + + + Keyman ausschalten + + + + Keyman Menü öffnen + + + + Bildschirmtastatur anzeigen + + + + Keyman Konfiguration öffnen + + + + Tastatur-Benutzungshilfe anzeigen + + + + Schriftart-Hilfe anzeigen + + + + Zeichentabelle anzeigen + + + + Texteditor öffnen + + + + Sprachumschaltung öffnen + + + + Allgemeine Tastenkürzel + + + + Tastaturlayouts + + + + Wenn Sie Probleme mit Keyman haben, stellen Sie einfach eine Frage im Keyman Community Forum. + + + + Keyman Community Forum öffnen + + + + Erstellt von SIL International + + + + Copyright 1994-2009 Tavultesoft Pty Ltd. Alle Rechte vorbehalten. + + + + Version + + + + Nützliche Links + + + + Tavultesoft Kundenbetreuung... + + + + Nach Updates suchen... + + + + Proxy-Einstellungen + + + + Keyman Systemeinstellungen... + + + + Diagnostik + + + + Tastatur von keyman.com herunterladen + + + + Nicht installieren, nur herunterladen + + + + + Kann Tastatur nicht herunterladen. Fehler %1:d: %0:s + + + + < Zurück + + + + Tastatur/Paket installieren + + + + Details + + + + Liesmich + + + + Installieren + + + + Proxy-Server-Konfiguration + + + + Server: + + + + Port: + + + + Benutzername: + + + + Passwort: + + + + Basis-Tastatur festlegen + + + + Wählen Sie die Tastatur mit lateinischer Schrift, die Sie in Windows verwenden. Keyman-Tastaturen werden automatisch an Ihr bevorzugtes Tastaturlayout angepasst. + + + + Tastenkürzel ändern + + + + + Standard-Tastenkürzel selektieren, oder \'Benutzerdefiniert\' auswählen und Strg, Umschalt- und/oder Alt- sowie gewünschte Taste für die Sprache %0:s drücken: + + + + Standard-Tastenkürzel selektieren, oder \'Benutzerdefiniert\' auswählen und Strg, Umschalt- und/oder Alt- sowie Taste für das gewünschte Tastaturkürzel drücken: + + + + + Das Tastenkürzel %0:s steht im Konflikt mit der normalen Tastatur. Sie sollten mindestens Strg oder Alt verwenden. Möchten Sie dies jetzt ändern? + + + + + Das Tastenkürzel %0:s steht im Konflikt zu dem ausgewählten Tastenkürzel für die %1:s-Tastatur. Wenn Sie fortfahren wird das Tastenkürzel für %1:s gelöscht. Fortfahren? + + + + + Das Tastenkürzel %0:s steht in Konflikt mit einem anderen Tastenkürzel. Wenn Sie fortfahren, wird das andere Tastenkürzel gelöscht. Fortfahren? + + + + Aktualisierte Keyman Komponenten verfügbar + + + + Es gibt Updates für Keyman + + + + Wählen Sie die Updates, die Sie installieren möchten: + + + + Sie können die neue Version herunterladen von: + + + + Jetzt installieren + + + + Abbrechen + + + + Alte Version + + + + Aktualisierte Komponente + + + + Größe + + + + + Keyman %0:s + + + + + %0:s-Tastatur %1:s + + + + Die keyman.com-Webseite ist nicht erreichbar - bitte testen Sie Ihre Internet-Verbindung, und versuchen Sie es erneut. + + + + + Die keyman.com-Webseite ist nicht erreichbar - bitte testen Sie Ihre Internet-Verbindung, und versuchen Sie es erneut. Der Fehler war: %0:s + + + + Keyman Updates sind verfügbar + + + + Klicken Sie auf dieses Symbol um Updates herunterzuladen und zu installieren + + + + Keyman Updates anzeigen und &installieren + + + + Update-Überprüfung &beenden + + + + Keyman + + + + Keyman starten + + + + Beenden + + + + Konfiguration + + + + Diesen Bildschirm beim Start anzeigen + + + + Anzeigen in + + + + Weitere Anzeigesprachen online finden... + + + + Helfen Sie mit, die Benutzeroberfläche zu übersetzen... + + + + Deutsch + + + + Deutsch (German) + + + + de + + + + en + + + + Keyman + + + + Hinweise zurücksetzen + + + + Alle Hinweise wurden zurückgesetzt und werden erneut angezeigt. + + + + + Keyman verlassen? + + + + + Sind Sie sicher, dass Sie Keyman verlassen möchten? Ihre Keyman-Tastaturen werden weiterhin in den Windows-Sprachen aufgelistet, werden aber erst dann funktionieren, wenn Sie Keyman neu starten. + + + + + Bildschirmtastatur geschlossen + + + + + Sie haben die Bildschirmtastatur geschlossen. Keyman läuft noch. Sie können die Bildschirmtastatur jederzeit öffnen, indem Sie auf das Tastatur-Symbol klicken und „Bildschirmtastatur“ wählen + + + + Diesen Hinweis nicht mehr anzeigen + + + + Keyman Hilfe + + + + Hilfe-Inhalte + + + + Hilfe zu \" + + + + \" Tastatur + + + + Bildschirmtastatur anzeigen + + + + Tastatur-Nutzung anzeigen + + + + Schriftarten anzeigen + + + + Zeichentabelle anzeigen + + + + Keyman Konfiguration öffnen + + + + Hilfe öffnen + + + + Bildschirmtastatur schließen + + + + Keyman &ausschalten + + + + &Bildschirmtastatur + + + + Tastatur-&Verwendung + + + + &Schriftarten-Anzeige + + + + &Zeichentabelle + + + + &Text-Editor... + + + + &Konfiguration... + + + + &Hilfe... + + + + &Verlassen + + + + Bei Inaktivität ausblenden + + + + Symbolleiste anzeigen + + + + Als Webseite speichern... + + + + Drucken... + + + + Keyman + + + + + Version %0:s + + + + &Drucken... + + + + + Ein Paket mit dem Namen %0:s ist bereits installiert. Möchten Sie es deinstallieren und das neue installieren? + + + + + Eine Tastatur mit dem Name \'%0:s\' ist bereits installiert. Wenn Sie fortfahren, wird sie deinstalliert bevor die neue Tastatur installiert wird. Fortfahren? + + + + + Die Tastatur \'%0:s\' ist Teil des Pakets \'%1:s\'. Sie müssen das gesamte Paket deinstallieren. Fortfahren? + + + + + Das Paket oder die Tastatur \'%0:s\' enthält keine Einführungshilfe. + + + + Dieses Betriebssystem wird nicht unterstützt. + + + + KeymanDesktop.chm + + + + Die Hilfedatei konnte nicht gefunden werden. + + + + Codepage + + + + Unicode + + + + Datei wird heruntergeladen + + + + + Sind Sie sicher, dass Sie die Bildschirmtastatur für %0:s entfernen möchten? + + + + + Sind Sie sicher, dass Sie die Tastatur %0:s deinstallieren wollen? + + + + + Sind Sie sicher, dass Sie das Tastaturbelegungspaket %0:s deinstallieren wollen? + +%1:s + + + + + Die folgenden Schriftarten werden ebenfalls deinstalliert: %0:s. + + + + Die Zeichentabelle enthält eine Datenbank von Zeichen, die erstellt werden muss, bevor sie verwendet werden kann. Jetzt erstellen? + + + + + Die Unicode Zeichen-Datenbank konnte nicht gelöscht werden für einen Wiederaufbau. Der Fehler ist: %0:s + + + + + Die Unicode Zeichen-Datenbank konnte nicht erstellt werden und wurde deaktiviert. Der Fehler ist: %0:s + + + + + Die Unicode Zeichen-Datenbank konnte nicht geladen werden (%0:s). Jetzt neu erstellen? + + + + + Keyman konnte nicht gestartet werden. Bevor Sie fortfahren überprüfen Sie bitte Ihre Sicherheitseinstellungen, um sicherzustellen, dass das Programm keyman.exe gestartet werden darf. Der gemeldete Fehler ist: + +\"%0:s\" + +Möchten Sie Keyman erneut starten? + + + + Keyman Debug-Informationen werden in einer Protokolldatei mit dem Namen %LOCALAPPDATA%\Keyman\Diag\system#.etl gespeichert (wobei # eine Nummer ist). Sie sollten Keyman beenden, bevor Sie diese Datei löschen. + +WARNUNG: Diese Datei kann sehr schnell groß werden. Das Aktivieren der Debug-Protokollierung kann Ihr System verlangsamen und sollte nur auf Anweisung durch den technischen Support erfolgen. + +DATENSCHUTZ-HINWEIS: Bitte beachten Sie, dass die Debug-Logdatei alle von Ihnen eingegebenen Tastenanschläge aufzeichnet. Sie sollten das Debug-Log nur für die Dauer einer Debugging- oder Diagnosesitzung aktivieren. + + + + Bitte warten Sie, während nach Schriftarten für Tastatur %0:s gesucht wird + + + + Tastatur %0:s ist keine Unicode-Tastatur. Schriftarten können nicht automatisch gefunden werden. Bitte überprüfen Sie die Tastaturdokumentation für Schriftarten. + + + + Derzeit sind keine Tastaturlayouts installiert oder geladen. + + + + Bitte wählen Sie eine Keyman-Tastatur, um unterstützte Schriftarten zu finden. + + + + Texteditor - Keyman diff --git a/windows/src/desktop/kmshell/xml/strings.xml b/windows/src/desktop/kmshell/xml/strings.xml index f09a01d348..75d0cc9569 100644 --- a/windows/src/desktop/kmshell/xml/strings.xml +++ b/windows/src/desktop/kmshell/xml/strings.xml @@ -439,7 +439,7 @@ - Always elevate user permissions when running in Windows Vista + Always elevate user permissions when running in Windows Vista @@ -471,7 +471,7 @@ - Open Keyboard Menu + Open Keyboard Menu @@ -1193,7 +1193,7 @@ PRIVACY WARNING: Please note that the debug logfile records all keystrokes that - Please wait while searching for releted fonts for keyboard %0:s + Please wait while searching for related fonts for keyboard %0:s diff --git a/windows/src/desktop/setup/locale/de/strings.xml b/windows/src/desktop/setup/locale/de/strings.xml new file mode 100644 index 0000000000..7622a24850 --- /dev/null +++ b/windows/src/desktop/setup/locale/de/strings.xml @@ -0,0 +1,80 @@ + + + Englisch + $APPNAME $VERSION Setup + Installiere $APPNAME $VERSION + $APPNAME $VERSION wurde erfolgreich installiert. + Sind Sie sicher, dass Sie die Installation von $APPNAME abbrechen möchten? + Entpacke Dateien... + Pakete werden überprüft... + Prüfe online auf Updates... + Installierte Versionen werden überprüft... + Fertigstellen... + + • $APPNAME %0:s %1:s + + • %0:s %1:s %2:s + + • %0:s %1:s für %2:s %3:s + Es gibt nichts zu installieren. + + (%0:s herunterladen) + Setup installiert: + $APPNAME $VERSION ist kostenlos und Open Source + &Lizenzbedingungen + Installati&ons-Einstellungen + $APPNAME Einstellungen + Ok + &Installieren + Abbrechen + &Beenden + Installiere $APPNAME + Ältere Versionen entfernen + Installation abgeschlossen + Sie müssen Windows neu starten, bevor das Setup abgeschlossen werden kann. Wenn Sie Windows neu starten, wird das Setup fortgesetzt. + +Jetzt neu starten? + Windows konnte nicht automatisch neu gestartet werden. Sie sollten Windows neu starten, bevor Sie $APPNAME starten. + Sie müssen Windows neu starten, um die Installation abzuschließen. Wenn Sie Windows neu starten, wird Setup beendet. + $APPNAME $VERSION benötigt Windows 7 oder höher, aber Keyman Desktop 7, 8 oder 9 wurde erkannt. Möchten Sie die in diesem Installer enthaltenen Tastaturen in die erkannte Keyman Desktop Version installieren? + Diese Version von $APPNAME benötigt Windows 7 oder neuer. Möchten Sie Keyman Desktop 8 herunterladen? + Installations-Optionen + Installationseinstellungen + Standard $APPNAME Einstellungen + Zu installierende oder aktualisierende Module + Verknüpfte Tastatursprache + Zu installierende Version + $APPNAME starten, wenn Windows startet + $APPNAME starten, wenn die Installation abgeschlossen ist + Automatisch nach Aktualisierungen suchen + Mit älteren Versionen installierte Tastaturen auf Version $VERSION aktualisieren + Anonyme Nutzungsstatistiken mit keyman.com teilen + + Setup-Version: %0:s + $APPNAME installieren + $APPNAME upgraden + + $APPNAME %0:s ist bereits installiert. + + Version %0:s herunterladen (%1:s) + + Version %0:s + + Installiere %0:s + + Version %0:s herunterladen (%1:s) + + Version %0:s + + Wählen Sie die Sprache aus, die Sie mit der Tastatur %0:s verknüpfen möchten + Default-Sprache + + Herunterladen von %0:s + + Herunterladen von %0:s + $APPNAME Setup konnte keine Verbindung zu keyman.com herstellen, um zusätzliche Ressourcen herunterzuladen. + +Bitte überprüfen Sie, ob Sie online sind, und geben Sie $APPNAME Setup in Ihren Firewall-Einstellungen die Erlaubnis, auf das Internet zuzugreifen. + +Klicken Sie auf Abbrechen, um die Einrichtung zu beenden, erneut zu versuchen und Ressourcen erneut herunterzuladen, oder ignorieren Sie, um offline fortzufahren. + diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index cc048fb3d9..80d90f2fc2 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -201,6 +201,7 @@ typedef struct tagKEYMAN64THREADDATA LPWORD IndexStack; LPWSTR miniContext; + int miniContextIfLen; KMSTATE state; diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 41b8d0b87d..5edda2331f 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -426,6 +426,8 @@ BOOL ProcessGroup(LPGROUP gp) assert(kkp != NULL); + _td->miniContextIfLen = xstrlen(kkp->dpContext) - xstrlen_ignoreifopt(kkp->dpContext); + // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support if(*kkp->dpContext == UC_SENTINEL && *(kkp->dpContext+1) == CODE_NUL) wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)-1), GLOBAL_ContextStackSize); // I3162 // I3536 @@ -549,18 +551,14 @@ int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr) _td->app->QueueAction(QIT_BELL, 0); break; case CODE_CONTEXT: // copy the context to the output - for(q = _td->miniContext; *q; q++) { - _td->app->QueueAction(QIT_CHAR, *q); - } - break; + PostString(_td->miniContext, mp, lpkb, wcschr(_td->miniContext, 0)); + break; case CODE_CONTEXTEX: p++; - for(q = _td->miniContext, i = 0; *q && i < *p-1; i++, q=incxstr(q)); + for(q = _td->miniContext, i = _td->miniContextIfLen; *q && i < *p-1; i++, q=incxstr(q)); if(*q) { - _td->app->QueueAction(QIT_CHAR, *q); - if(Uni_IsSurrogate1(*q) && Uni_IsSurrogate2(*(q+1))) { - _td->app->QueueAction(QIT_CHAR, *(q+1)); - } + temp = incxstr(q); + PostString(q, mp, lpkb, temp); } break; case CODE_RETURN: // stop processing and start PostAllKeys diff --git a/windows/src/ext/sentry/Sentry.Client.pas b/windows/src/ext/sentry/Sentry.Client.pas index 93e177377f..fc823bfaa7 100644 --- a/windows/src/ext/sentry/Sentry.Client.pas +++ b/windows/src/ext/sentry/Sentry.Client.pas @@ -55,6 +55,8 @@ type protected class var FInstance: TSentryClient; + FEnabled: Boolean; + FEnabledInitialised: Boolean; private FSentryInit: Boolean; options: psentry_options_t; @@ -73,6 +75,7 @@ type procedure DoTerminate; function EventIDToString(AGuid: PByte): String; function ConvertRawStackToSentryStack(wrapWithThread: Boolean): sentry_value_t; + class function GetEnabled: Boolean; static; public constructor Create(AOptions: TSentryClientOptions; const ALogger: string; AFlags: TSentryClientFlags); virtual; destructor Destroy; override; @@ -85,6 +88,8 @@ type property ReportExceptions: Boolean read FReportExceptions; property ReportMessages: Boolean read FReportMessages; + public + class property Enabled: Boolean read GetEnabled; end; TSentryClientClass = class of TSentryClient; @@ -431,6 +436,19 @@ begin end; end; +class function TSentryClient.GetEnabled: Boolean; +begin + if not FEnabledInitialised then + begin + // WINE is not coping with some of the Sentry/dbghelp calls so disable + // sentry on WINE instances. + FEnabled := GetProcAddress(GetModuleHandle('ntdll.dll'), 'wine_get_version') = nil; + FEnabledInitialised := True; + end; + + Exit(FEnabled); +end; + function TSentryClient.MessageEvent(Level: TSentryLevel; const Message: string; IncludeStack: Boolean): string; var @@ -576,6 +594,7 @@ initialization SymGetModuleBase64 := GetProcAddress(hDbgHelp, 'SymGetModuleBase64'); SymInitialize := GetProcAddress(hDbgHelp, 'SymInitialize'); - if Assigned(SymInitialize) then - SymInitialize(GetCurrentProcess, nil, True); + if TSentryClient.Enabled then + if Assigned(SymInitialize) then + SymInitialize(GetCurrentProcess, nil, True); end. diff --git a/windows/src/global/delphi/general/Keyman.System.KeymanSentryClient.pas b/windows/src/global/delphi/general/Keyman.System.KeymanSentryClient.pas index 2ae69a9b44..095f94ce84 100644 --- a/windows/src/global/delphi/general/Keyman.System.KeymanSentryClient.pas +++ b/windows/src/global/delphi/general/Keyman.System.KeymanSentryClient.pas @@ -27,6 +27,7 @@ type procedure NestedValidateAccessViolation; procedure NestedValidateDelphiException; procedure NestedValidateFloatingPointException; + class function GetEnabled: Boolean; static; public destructor Destroy; override; @@ -37,6 +38,7 @@ type class procedure Start(SentryClientClass: TSentryClientClass; AProject: TKeymanSentryClientProject; const ALogger: string; AFlags: TKeymanSentryClientFlags = [kscfCaptureExceptions, kscfShowUI, kscfTerminate]); class procedure Stop; class property Client: TSentryClient read FClient; + class property Enabled: Boolean read GetEnabled; class property Instance: TKeymanSentryClient read FInstance; class property OnBeforeShutdown: TNotifyEvent read FOnBeforeShutdown write FOnBeforeShutdown; public @@ -186,6 +188,9 @@ class procedure TKeymanSentryClient.ReportHandledException(E: Exception; var text: string; begin + if not Enabled then + Exit; + if Message <> '' then text := Message + ': ' else text := ''; @@ -285,6 +290,9 @@ begin FProject := AProject; FFlags := AFlags; + if not Enabled then + Exit; + sentry_set_library_path(FindSentryDLL); o.Debug := False; @@ -346,6 +354,11 @@ begin inherited Destroy; end; +class function TKeymanSentryClient.GetEnabled: Boolean; +begin + Result := TSentryClient.Enabled; +end; + class procedure TKeymanSentryClient.Start(SentryClientClass: TSentryClientClass; AProject: TKeymanSentryClientProject; const ALogger: string; AFlags: TKeymanSentryClientFlags); begin TKeymanSentryClient.Create(SentryClientClass, AProject, ALogger, AFlags); @@ -367,6 +380,9 @@ end; // class procedure TKeymanSentryClient.Validate(Force: Boolean); begin + if not Enabled then + Exit; + TKeymanSentryClient.Instance.NestedValidate(Force); end; diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/.gitignore b/windows/src/test/GH-4275 - contextex-mismatch-with-if/.gitignore new file mode 100644 index 0000000000..d16386367f --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/HISTORY.md b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/HISTORY.md new file mode 100644 index 0000000000..aa1753a70b --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/HISTORY.md @@ -0,0 +1,6 @@ +context_mismatch_with_if Change History +==================== + +1.0 (2021-01-18) +---------------- +* Created by Andrew Cunningham / Marc Durdin diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/LICENSE.md b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/LICENSE.md new file mode 100644 index 0000000000..9f5de40a84 --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +© 2021 SIL International + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/README.md b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/README.md new file mode 100644 index 0000000000..c80822652a --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/README.md @@ -0,0 +1,29 @@ +context_mismatch_with_if keyboard +============== + +© 2021 SIL International + +Version 1.0 + +Description +----------- + +See https://github.com/keymanapp/keyman/issues/4275 + +Links +----- + +Supported Platforms +------------------- + * Windows + * macOS + * Linux + * Web + * iPhone + * iPad + * Android phone + * Android tablet + * Mobile devices + * Desktop devices + * Tablet devices + diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/context_mismatch_with_if.keyboard_info b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/context_mismatch_with_if.keyboard_info new file mode 100644 index 0000000000..5ce314be00 --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/context_mismatch_with_if.keyboard_info @@ -0,0 +1,7 @@ +{ + "license": "mit", + "languages": [ + "din-Latn" + ], + "description": "context_mismatch_with_if generated from template" +} diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/context_mismatch_with_if.kpj b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/context_mismatch_with_if.kpj new file mode 100644 index 0000000000..88a7bc90ba --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/context_mismatch_with_if.kpj @@ -0,0 +1,102 @@ + + + + $PROJECTPATH\build + True + True + True + keyboard + + + + id_d4e154080bd02f7d130d0c8150afeed5 + context_mismatch_with_if.kmn + source\context_mismatch_with_if.kmn + 1.0 + .kmn +
+ context_mismatch_with_if + © 2021 Andrew Cunningham / Marc Durdin +
+
+ + id_fff45ad33955e3efc776aacdf99d136b + context_mismatch_with_if.kps + source\context_mismatch_with_if.kps + + .kps +
+ context_mismatch_with_if + © +
+
+ + id_ede98e4633e239f933cbfd1f4e1b766c + HISTORY.md + HISTORY.md + + .md + + + id_53e892b8b41cc4caece1cfd5ef21d6e7 + LICENSE.md + LICENSE.md + + .md + + + id_0730bb7c2e8f9ea2438b52e419dd86c9 + README.md + README.md + + .md + + + id_1213256b2009e2b32ee7d551a63402c6 + context_mismatch_with_if.keyboard_info + context_mismatch_with_if.keyboard_info + + .keyboard_info + + + id_ea1380e11b2491a95b183d9ea2bcd813 + context_mismatch_with_if.kmx + source\..\build\context_mismatch_with_if.kmx + + .kmx + id_fff45ad33955e3efc776aacdf99d136b + + + id_d038ab27468705cf4f13a191d3e065a4 + context_mismatch_with_if.js + source\..\build\context_mismatch_with_if.js + + .js + id_fff45ad33955e3efc776aacdf99d136b + + + id_7465a6bfd4f4080c7a939af65ae62ea9 + context_mismatch_with_if.kvk + source\..\build\context_mismatch_with_if.kvk + + .kvk + id_fff45ad33955e3efc776aacdf99d136b + + + id_356e5d149c1e539356d72698c1e401a6 + welcome.htm + source\welcome.htm + + .htm + id_fff45ad33955e3efc776aacdf99d136b + + + id_8da344c4cea6f467013357fe099006f5 + readme.htm + source\readme.htm + + .htm + id_fff45ad33955e3efc776aacdf99d136b + +
+
diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.keyman-touch-layout b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.keyman-touch-layout new file mode 100644 index 0000000000..149069b062 --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.keyman-touch-layout @@ -0,0 +1,1316 @@ +{ + "tablet": { + "font": "Tahoma", + "layer": [ + { + "id": "default", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_Q", + "text": "q" + }, + { + "id": "K_W", + "text": "w" + }, + { + "id": "K_E", + "text": "e" + }, + { + "id": "K_R", + "text": "r" + }, + { + "id": "K_T", + "text": "t" + }, + { + "id": "K_Y", + "text": "y" + }, + { + "id": "K_U", + "text": "u" + }, + { + "id": "K_I", + "text": "i" + }, + { + "id": "K_O", + "text": "o" + }, + { + "id": "K_P", + "text": "p" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_A", + "text": "a", + "pad": 70 + }, + { + "id": "K_S", + "text": "s" + }, + { + "id": "K_D", + "text": "d" + }, + { + "id": "K_F", + "text": "f" + }, + { + "id": "K_G", + "text": "g" + }, + { + "id": "K_H", + "text": "h" + }, + { + "id": "K_J", + "text": "j" + }, + { + "id": "K_K", + "text": "k" + }, + { + "id": "K_L", + "text": "l" + }, + { + "sp": "10", + "width": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "110", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "K_Z", + "text": "z" + }, + { + "id": "K_X", + "text": "x" + }, + { + "id": "K_C", + "text": "c" + }, + { + "id": "K_V", + "text": "v" + }, + { + "id": "K_B", + "text": "b" + }, + { + "id": "K_N", + "text": "n" + }, + { + "id": "K_M", + "text": "m" + }, + { + "id": "K_PERIOD", + "text": ".", + "sk": [ + { + "text": ",", + "id": "K_COMMA" + }, + { + "text": "!", + "id": "K_1", + "layer": "shift" + }, + { + "text": "?", + "id": "K_SLASH", + "layer": "shift" + }, + { + "text": "'", + "id": "K_QUOTE" + }, + { + "text": "\"", + "id": "K_QUOTE", + "layer": "shift" + }, + { + "text": "\\", + "id": "K_BKSLASH" + }, + { + "text": ":", + "id": "K_COLON", + "layer": "shift" + }, + { + "text": ";", + "id": "K_COLON" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "90", + "sp": "1" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_NUMLOCK", + "text": "*123*", + "width": "140", + "sp": "1", + "nextlayer": "numeric" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "120", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "630", + "sp": "0" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "140", + "sp": "1" + } + ] + } + ] + }, + { + "id": "shift", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_Q", + "text": "Q" + }, + { + "id": "K_W", + "text": "W" + }, + { + "id": "K_E", + "text": "E" + }, + { + "id": "K_R", + "text": "R" + }, + { + "id": "K_T", + "text": "T" + }, + { + "id": "K_Y", + "text": "Y" + }, + { + "id": "K_U", + "text": "U" + }, + { + "id": "K_I", + "text": "I" + }, + { + "id": "K_O", + "text": "O" + }, + { + "id": "K_P", + "text": "P" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_A", + "text": "A", + "pad": 70 + }, + { + "id": "K_S", + "text": "S" + }, + { + "id": "K_D", + "text": "D" + }, + { + "id": "K_F", + "text": "F" + }, + { + "id": "K_G", + "text": "G" + }, + { + "id": "K_H", + "text": "H" + }, + { + "id": "K_J", + "text": "J" + }, + { + "id": "K_K", + "text": "K" + }, + { + "id": "K_L", + "text": "L" + }, + { + "sp": "10", + "width": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "110", + "sp": "2", + "nextlayer": "default" + }, + { + "id": "K_Z", + "text": "Z" + }, + { + "id": "K_X", + "text": "X" + }, + { + "id": "K_C", + "text": "C" + }, + { + "id": "K_V", + "text": "V" + }, + { + "id": "K_B", + "text": "B" + }, + { + "id": "K_N", + "text": "N" + }, + { + "id": "K_M", + "text": "M" + }, + { + "id": "K_PERIOD", + "text": ".", + "layer": "default", + "sk": [ + { + "text": ",", + "id": "K_COMMA", + "layer": "default" + }, + { + "text": "!", + "id": "K_1", + "layer": "shift" + }, + { + "text": "?", + "id": "K_SLASH", + "layer": "shift" + }, + { + "text": "'", + "id": "K_QUOTE", + "layer": "default" + }, + { + "text": "\"", + "id": "K_QUOTE", + "layer": "shift" + }, + { + "text": "\\", + "id": "K_BKSLASH", + "layer": "default" + }, + { + "text": ":", + "id": "K_COLON", + "layer": "shift" + }, + { + "text": ";", + "id": "K_COLON", + "layer": "default" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "90", + "sp": "1" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_NUMLOCK", + "text": "*123*", + "width": "140", + "sp": "1", + "nextlayer": "numeric" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "120", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "630", + "sp": "0" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "140", + "sp": "1" + } + ] + } + ] + }, + { + "id": "numeric", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "1" + }, + { + "id": "K_2", + "text": "2" + }, + { + "id": "K_3", + "text": "3" + }, + { + "id": "K_4", + "text": "4" + }, + { + "id": "K_5", + "text": "5" + }, + { + "id": "K_6", + "text": "6" + }, + { + "id": "K_7", + "text": "7" + }, + { + "id": "K_8", + "text": "8" + }, + { + "id": "K_9", + "text": "9" + }, + { + "id": "K_0", + "text": "0" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_4", + "text": "$", + "layer": "shift", + "pad": 70 + }, + { + "id": "K_2", + "text": "@", + "layer": "shift" + }, + { + "id": "K_3", + "text": "#", + "layer": "shift" + }, + { + "id": "K_5", + "text": "%", + "layer": "shift" + }, + { + "id": "K_7", + "text": "&", + "layer": "shift" + }, + { + "id": "K_HYPHEN", + "text": "_", + "layer": "shift" + }, + { + "id": "K_EQUAL", + "text": "=", + "layer": "default" + }, + { + "id": "K_BKSLASH", + "text": "|", + "layer": "shift" + }, + { + "id": "K_BKSLASH", + "text": "\\", + "layer": "default" + }, + { + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "110", + "sp": "1" + }, + { + "id": "K_LBRKT", + "text": "[", + "sk": [ + { + "id": "U_00AB", + "text": "\u00AB" + }, + { + "id": "K_COMMA", + "text": "<", + "layer": "shift" + }, + { + "id": "K_LBRKT", + "text": "{", + "layer": "shift" + } + ] + }, + { + "id": "K_9", + "text": "(", + "layer": "shift" + }, + { + "id": "K_0", + "text": ")", + "layer": "shift" + }, + { + "id": "K_RBRKT", + "text": "]", + "sk": [ + { + "id": "U_00BB", + "text": "\u00BB" + }, + { + "id": "K_PERIOD", + "text": ">", + "layer": "shift" + }, + { + "id": "K_RBRKT", + "text": "}", + "layer": "shift" + } + ] + }, + { + "id": "K_EQUAL", + "text": "+", + "layer": "shift" + }, + { + "id": "K_HYPHEN", + "text": "-", + "layer": "default" + }, + { + "id": "K_8", + "text": "*", + "layer": "shift" + }, + { + "id": "K_SLASH", + "text": "/", + "layer": "default" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "90", + "sp": "1" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_LOWER", + "text": "*abc*", + "width": "140", + "sp": "1", + "nextlayer": "default" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "120", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "630", + "sp": "0" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "140", + "sp": "1" + } + ] + } + ] + } + ] + }, + "phone": { + "font": "Tahoma", + "layer": [ + { + "id": "default", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_Q", + "text": "q" + }, + { + "id": "K_W", + "text": "w" + }, + { + "id": "K_E", + "text": "e" + }, + { + "id": "K_R", + "text": "r" + }, + { + "id": "K_T", + "text": "t" + }, + { + "id": "K_Y", + "text": "y" + }, + { + "id": "K_U", + "text": "u" + }, + { + "id": "K_I", + "text": "i" + }, + { + "id": "K_O", + "text": "o" + }, + { + "id": "K_P", + "text": "p" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_A", + "text": "a", + "pad": "50" + }, + { + "id": "K_S", + "text": "s" + }, + { + "id": "K_D", + "text": "d" + }, + { + "id": "K_F", + "text": "f" + }, + { + "id": "K_G", + "text": "g" + }, + { + "id": "K_H", + "text": "h" + }, + { + "id": "K_J", + "text": "j" + }, + { + "id": "K_K", + "text": "k" + }, + { + "id": "K_L", + "text": "l" + }, + { + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "K_Z", + "text": "z" + }, + { + "id": "K_X", + "text": "x" + }, + { + "id": "K_C", + "text": "c" + }, + { + "id": "K_V", + "text": "v" + }, + { + "id": "K_B", + "text": "b" + }, + { + "id": "K_N", + "text": "n" + }, + { + "id": "K_M", + "text": "m" + }, + { + "id": "K_PERIOD", + "text": ".", + "sk": [ + { + "text": ",", + "id": "K_COMMA" + }, + { + "text": "!", + "id": "K_1", + "layer": "shift" + }, + { + "text": "?", + "id": "K_SLASH", + "layer": "shift" + }, + { + "text": "'", + "id": "K_QUOTE" + }, + { + "text": "\"", + "id": "K_QUOTE", + "layer": "shift" + }, + { + "text": "\\", + "id": "K_BKSLASH" + }, + { + "text": ":", + "id": "K_COLON", + "layer": "shift" + }, + { + "text": ";", + "id": "K_COLON" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_NUMLOCK", + "text": "*123*", + "width": "150", + "sp": "1", + "nextlayer": "numeric" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "120", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "610", + "sp": "0" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "150", + "sp": "1" + } + ] + } + ] + }, + { + "id": "shift", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_Q", + "text": "Q" + }, + { + "id": "K_W", + "text": "W" + }, + { + "id": "K_E", + "text": "E" + }, + { + "id": "K_R", + "text": "R" + }, + { + "id": "K_T", + "text": "T" + }, + { + "id": "K_Y", + "text": "Y" + }, + { + "id": "K_U", + "text": "U" + }, + { + "id": "K_I", + "text": "I" + }, + { + "id": "K_O", + "text": "O" + }, + { + "id": "K_P", + "text": "P" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_A", + "text": "A", + "pad": "50" + }, + { + "id": "K_S", + "text": "S" + }, + { + "id": "K_D", + "text": "D" + }, + { + "id": "K_F", + "text": "F" + }, + { + "id": "K_G", + "text": "G" + }, + { + "id": "K_H", + "text": "H" + }, + { + "id": "K_J", + "text": "J" + }, + { + "id": "K_K", + "text": "K" + }, + { + "id": "K_L", + "text": "L" + }, + { + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "sp": "2", + "nextlayer": "default" + }, + { + "id": "K_Z", + "text": "Z" + }, + { + "id": "K_X", + "text": "X" + }, + { + "id": "K_C", + "text": "C" + }, + { + "id": "K_V", + "text": "V" + }, + { + "id": "K_B", + "text": "B" + }, + { + "id": "K_N", + "text": "N" + }, + { + "id": "K_M", + "text": "M" + }, + { + "id": "K_PERIOD", + "text": ".", + "layer": "default", + "sk": [ + { + "text": ",", + "id": "K_COMMA", + "layer": "default" + }, + { + "text": "!", + "id": "K_1", + "layer": "shift" + }, + { + "text": "?", + "id": "K_SLASH", + "layer": "shift" + }, + { + "text": "'", + "id": "K_QUOTE", + "layer": "default" + }, + { + "text": "\"", + "id": "K_QUOTE", + "layer": "shift" + }, + { + "text": "\\", + "id": "K_BKSLASH", + "layer": "default" + }, + { + "text": ":", + "id": "K_COLON", + "layer": "shift" + }, + { + "text": ";", + "id": "K_COLON", + "layer": "default" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "sp": "1" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_NUMLOCK", + "text": "*123*", + "width": "150", + "sp": "1", + "nextlayer": "numeric" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "120", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "610", + "sp": "0" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "150", + "sp": "1" + } + ] + } + ] + }, + { + "id": "numeric", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "1" + }, + { + "id": "K_2", + "text": "2" + }, + { + "id": "K_3", + "text": "3" + }, + { + "id": "K_4", + "text": "4" + }, + { + "id": "K_5", + "text": "5" + }, + { + "id": "K_6", + "text": "6" + }, + { + "id": "K_7", + "text": "7" + }, + { + "id": "K_8", + "text": "8" + }, + { + "id": "K_9", + "text": "9" + }, + { + "id": "K_0", + "text": "0" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_4", + "layer": "shift", + "text": "$", + "pad": "50" + }, + { + "id": "K_2", + "layer": "shift", + "text": "@" + }, + { + "id": "K_3", + "layer": "shift", + "text": "#" + }, + { + "id": "K_5", + "layer": "shift", + "text": "%" + }, + { + "id": "K_6", + "layer": "shift", + "text": "&" + }, + { + "id": "K_HYPHEN", + "layer": "shift", + "text": "_" + }, + { + "id": "K_EQUAL", + "text": "=", + "layer": "default" + }, + { + "id": "K_BKSLASH", + "layer": "shift", + "text": "|" + }, + { + "id": "K_BKSLASH", + "text": "\\", + "layer": "default" + }, + { + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_LBRKT", + "text": "[", + "pad": "110", + "sk": [ + { + "id": "U_00AB", + "text": "\u00AB" + }, + { + "id": "K_COMMA", + "text": "<", + "layer": "shift" + }, + { + "id": "K_LBRKT", + "text": "{", + "layer": "shift" + } + ] + }, + { + "id": "K_9", + "layer": "shift", + "text": "(" + }, + { + "id": "K_0", + "layer": "shift", + "text": ")" + }, + { + "id": "K_RBRKT", + "text": "]", + "sk": [ + { + "id": "U_00BB", + "text": "\u00BB" + }, + { + "id": "K_PERIOD", + "text": ">", + "layer": "shift" + }, + { + "id": "K_RBRKT", + "text": "}", + "layer": "shift" + } + ] + }, + { + "id": "K_EQUAL", + "layer": "shift", + "text": "+" + }, + { + "id": "K_HYPHEN", + "text": "-" + }, + { + "id": "K_8", + "layer": "shift", + "text": "*" + }, + { + "id": "K_SLASH", + "text": "/" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_LOWER", + "text": "*abc*", + "width": "150", + "sp": "1", + "nextlayer": "default" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "120", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "610", + "sp": "0" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "150", + "sp": "1" + } + ] + } + ] + } + ] + } +} diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kmn b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kmn new file mode 100644 index 0000000000..2cd240da8d --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kmn @@ -0,0 +1,60 @@ +c Tests context(n) together with if() and BKSP, as reported by +c Andrew Cunningham. + +c +c Tests: +c +c 1. [x][BKSP] should result in "a" U+0308 +c -> 14.0.223 gives U+0308 "e" +c 2. [y][z] should result in '<' dk(1) 'a' dk(2) 'b' dk(3) '>' +c -> 14.0.223 gives 'ab>' (note the missing initial '<'!) +c 3. [y][M] should result in '<' dk(1) '>' +c -> 14.0.223 gives '<' U+FFFF '>' +c (to test on web, type [y][M][?], which should result in 'correct', as it is +c difficult to observe deadkeys) +c +c Note: all these tests pass on web. +c + + +store(&VERSION) '10.0' +store(&NAME) 'context_mismatch_with_if' +store(©RIGHT) '© 2021 Andrew Cunningham / Marc Durdin' +store(&TARGETS) 'any' + +begin Unicode > use(constraints) + +store(nfc) '0' c 1 (default) = Normalisation Form C, 0 = Normalisation Form D +store(diaeresisBase) U+0061 U+0041 U+0065 U+0045 U+0069 U+0049 U+006F U+004F c a A e E i I o O + +group(constraints) using keys + +c ######################## +c character position tests +c ######################## + +c Setup + ++ 'x' > 'a' U+0308 'e' U+0308 + +c Test #1 for if() with context(n) + +if(nfc = "0") any(diaeresisBase) U+0308 any(diaeresisBase) U+0308 + [K_BKSP] > context(2) context(3) + +c ########################## +c deadkeys and context tests +c ########################## + +c Setup + ++ 'y' > dk(1) 'a' dk(2) 'b' dk(3) + +c Test #2 for dk(d) and context + +dk(1) 'a' dk(2) 'b' dk(3) + 'z' > '<' context '>' +'<' dk(1) 'a' dk(2) 'b' dk(3) '>' + '?' > 'correct' + +c Test #3 for dk(d) and context(n) + +dk(1) 'a' dk(2) 'b' dk(3) + 'M' > '<' context(1) '>' +'<' dk(1) '>' + '?' > 'correct' diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kps b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kps new file mode 100644 index 0000000000..14b9ff2781 --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kps @@ -0,0 +1,67 @@ + + + + 13.0.9999.0 + 7.0 + + + + readme.htm + + + + + + + + + + context_mismatch_with_if + © + Andrew Cunningham / Marc Durdin + + + + + ..\build\context_mismatch_with_if.kmx + + 0 + .kmx + + + ..\build\context_mismatch_with_if.js + + 0 + .js + + + ..\build\context_mismatch_with_if.kvk + + 0 + .kvk + + + welcome.htm + + 0 + .htm + + + readme.htm + + 0 + .htm + + + + + context_mismatch_with_if + context_mismatch_with_if + 1.0 + + Dinka + + + + + diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kvks b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kvks new file mode 100644 index 0000000000..c6296b2572 --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/context_mismatch_with_if.kvks @@ -0,0 +1,8 @@ + + +
+ 10.0 + context_mismatch_with_if + +
+
diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/readme.htm b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/readme.htm new file mode 100644 index 0000000000..cde2c5da28 --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/readme.htm @@ -0,0 +1,24 @@ + + + + + + context_mismatch_with_if + + + + +

context_mismatch_with_if

+ +

+ context_mismatch_with_if 1.0 generated from template. +

+ +

©

+ + + diff --git a/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/welcome.htm b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/welcome.htm new file mode 100644 index 0000000000..5019a12b42 --- /dev/null +++ b/windows/src/test/GH-4275 - contextex-mismatch-with-if/context_mismatch_with_if/source/welcome.htm @@ -0,0 +1,28 @@ + + + + + + Start Using context_mismatch_with_if + + + + +

Start Using context_mismatch_with_if

+ +

+ context_mismatch_with_if 1.0 generated from template. +

+ +

Keyboard Layout

+ + + +

©

+ + + \ No newline at end of file diff --git a/windows/src/test/unit-tests/Makefile b/windows/src/test/unit-tests/Makefile index 9fdacbeb68..86b9790a59 100644 --- a/windows/src/test/unit-tests/Makefile +++ b/windows/src/test/unit-tests/Makefile @@ -34,12 +34,6 @@ lexical-model-compiler: start /wait ./build.sh -test !endif -# Revert any local changes to the original source; these changes can break -# later sub-builds. - cd $(KEYMAN_ROOT)\developer\js - git restore package.json - git restore package-lock.json - kmcomp-x64-structures: cd $(ROOT)\src\test\unit-tests\group-helper-rsp19902 $(MAKE) $(TARGET)