mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-22 00:12:09 +03:00
Change prefixes and add check_strings.py
This commit is contained in:
parent
fd1046eb72
commit
b33dca3900
110
check_strings.py
Executable file
110
check_strings.py
Executable file
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2023 Yubico.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
errors = []
|
||||
|
||||
|
||||
def check_duplicate_keys(pairs):
|
||||
seen = set()
|
||||
for d in [k for k, v in pairs if k in seen or seen.add(k)]:
|
||||
errors.append(f"Duplicate key: {d}")
|
||||
return dict(pairs)
|
||||
|
||||
|
||||
def check_duplicate_values(strings):
|
||||
seen = {}
|
||||
for k, v in strings.items():
|
||||
if isinstance(v, str):
|
||||
if v in seen:
|
||||
errors.append(
|
||||
f"Duplicate value in key: {k} (originally in {seen[v]}): {v}"
|
||||
)
|
||||
else:
|
||||
seen[v] = k
|
||||
|
||||
|
||||
def check_prefixes(k, v, s_max_words, s_max_len):
|
||||
errs = []
|
||||
if k.startswith("s_"):
|
||||
if len(v) > s_max_len:
|
||||
errs.append(f"Too long ({len(v)} chars)")
|
||||
if len(v.split()) > s_max_words:
|
||||
errs.append(f"Too many words ({len(v.split())})")
|
||||
elif k.startswith("l_"):
|
||||
if v.endswith("."):
|
||||
errs.append("Ends with '.'")
|
||||
if ". " in v:
|
||||
errs.append("Spans multiple sentences")
|
||||
elif k.startswith("p_"):
|
||||
if v[-1] not in ".!":
|
||||
errs.append("Doesn't end in punctuation")
|
||||
elif k.startswith("q_"):
|
||||
if not v.endswith("?"):
|
||||
errs.append("Doesn't end in '?'")
|
||||
return errs
|
||||
|
||||
|
||||
def check_misc(k, v):
|
||||
errs = []
|
||||
if "..." in v:
|
||||
errs.append("'...' should be replaced with '\\u2026'")
|
||||
return errs
|
||||
|
||||
|
||||
def lint_strings(strings, rules):
|
||||
for k, v in strings.items():
|
||||
errs = []
|
||||
errs.extend(
|
||||
check_prefixes(
|
||||
k,
|
||||
v,
|
||||
rules.get("s_max_words", 4),
|
||||
rules.get("s_max_len", 32),
|
||||
)
|
||||
)
|
||||
errs.extend(check_misc(k, v))
|
||||
if errs:
|
||||
errors.append(f'Errors in {k}: "{v}"')
|
||||
errors.extend([f" {e}" for e in errs])
|
||||
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print("USAGE: check_strings.py <ARB_FILE>")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
target = sys.argv[1]
|
||||
with open(target) as f:
|
||||
values = json.load(f, object_pairs_hook=check_duplicate_keys)
|
||||
|
||||
strings = {k: v for k, v in values.items() if not k.startswith("@")}
|
||||
|
||||
check_duplicate_values(strings)
|
||||
lint_strings(strings, strings.get("@_lint_rules", {}))
|
||||
|
||||
print(len(strings), "strings in file")
|
||||
|
||||
|
||||
if errors:
|
||||
for e in errors:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
print("OK")
|
@ -42,7 +42,7 @@ class AboutPage extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.w_about),
|
||||
title: Text(l10n.s_about),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
child: Column(
|
||||
@ -63,7 +63,7 @@ class AboutPage extends ConsumerWidget {
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
l10n.l_terms_of_use,
|
||||
l10n.s_terms_of_use,
|
||||
style:
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
@ -73,7 +73,7 @@ class AboutPage extends ConsumerWidget {
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
l10n.l_privacy_policy,
|
||||
l10n.s_privacy_policy,
|
||||
style:
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
@ -85,7 +85,7 @@ class AboutPage extends ConsumerWidget {
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
l10n.l_open_src_licenses,
|
||||
l10n.s_open_src_licenses,
|
||||
style: const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
@ -104,7 +104,7 @@ class AboutPage extends ConsumerWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Text(
|
||||
l10n.l_help_and_feedback,
|
||||
l10n.s_help_and_feedback,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
@ -113,7 +113,7 @@ class AboutPage extends ConsumerWidget {
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
l10n.l_send_feedback,
|
||||
l10n.s_send_feedback,
|
||||
style:
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
@ -123,7 +123,7 @@ class AboutPage extends ConsumerWidget {
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
l10n.l_i_need_help,
|
||||
l10n.s_i_need_help,
|
||||
style:
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
@ -140,7 +140,7 @@ class AboutPage extends ConsumerWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Text(
|
||||
l10n.w_troubleshooting,
|
||||
l10n.s_troubleshooting,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
@ -151,7 +151,7 @@ class AboutPage extends ConsumerWidget {
|
||||
const SizedBox(height: 12.0),
|
||||
ActionChip(
|
||||
avatar: const Icon(Icons.bug_report_outlined),
|
||||
label: Text(l10n.l_run_diagnostics),
|
||||
label: Text(l10n.s_run_diagnostics),
|
||||
onPressed: () async {
|
||||
_log.info('Running diagnostics...');
|
||||
final response = await ref
|
||||
@ -180,7 +180,7 @@ class AboutPage extends ConsumerWidget {
|
||||
if (isAndroid) ...[
|
||||
const SizedBox(height: 12.0),
|
||||
FilterChip(
|
||||
label: Text(l10n.l_allow_screenshots),
|
||||
label: Text(l10n.s_allow_screenshots),
|
||||
selected: ref.watch(androidAllowScreenshotsProvider),
|
||||
onSelected: (value) async {
|
||||
ref
|
||||
@ -216,7 +216,7 @@ class LoggingPanel extends ConsumerWidget {
|
||||
value: logLevel,
|
||||
items: Levels.LEVELS,
|
||||
selected: logLevel != Level.INFO,
|
||||
labelBuilder: (value) => Text(l10n.l_log_level(
|
||||
labelBuilder: (value) => Text(l10n.s_log_level(
|
||||
value.name[0] + value.name.substring(1).toLowerCase())),
|
||||
itemBuilder: (value) =>
|
||||
Text('${value.name[0]}${value.name.substring(1).toLowerCase()}'),
|
||||
@ -227,7 +227,7 @@ class LoggingPanel extends ConsumerWidget {
|
||||
),
|
||||
ActionChip(
|
||||
avatar: const Icon(Icons.copy),
|
||||
label: Text(l10n.l_copy_log),
|
||||
label: Text(l10n.s_copy_log),
|
||||
onPressed: () async {
|
||||
_log.info('Copying log to clipboard ($version)...');
|
||||
final logs = await ref.read(logLevelProvider.notifier).getLogs();
|
||||
|
@ -195,7 +195,7 @@ class _AndroidCredentialListNotifier extends OathCredentialListNotifier {
|
||||
return promptUserInteraction(
|
||||
context,
|
||||
icon: const Icon(Icons.touch_app),
|
||||
title: l10n.l_touch_required,
|
||||
title: l10n.s_touch_required,
|
||||
description: l10n.l_touch_button_now,
|
||||
);
|
||||
},
|
||||
|
@ -75,7 +75,7 @@ class QRScannerPermissionsUI extends StatelessWidget {
|
||||
Navigator.of(context).pop('');
|
||||
},
|
||||
child: Text(
|
||||
l10n.l_enter_manually,
|
||||
l10n.s_enter_manually,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
)),
|
||||
],
|
||||
@ -92,7 +92,7 @@ class QRScannerPermissionsUI extends StatelessWidget {
|
||||
onPermissionRequest();
|
||||
},
|
||||
child: Text(
|
||||
l10n.l_review_permissions,
|
||||
l10n.s_review_permissions,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
)),
|
||||
],
|
||||
|
@ -73,7 +73,7 @@ class QRScannerUI extends StatelessWidget {
|
||||
},
|
||||
key: keys.manualEntryButton,
|
||||
child: Text(
|
||||
l10n.l_enter_manually,
|
||||
l10n.s_enter_manually,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
)),
|
||||
],
|
||||
|
@ -114,7 +114,7 @@ class _QrScannerViewState extends State<QrScannerView> {
|
||||
extendBody: true,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
l10n.l_add_account,
|
||||
l10n.s_add_account,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
|
@ -80,11 +80,11 @@ extension on ThemeMode {
|
||||
String getDisplayName(AppLocalizations l10n) {
|
||||
switch (this) {
|
||||
case ThemeMode.system:
|
||||
return l10n.l_system_default;
|
||||
return l10n.s_system_default;
|
||||
case ThemeMode.light:
|
||||
return l10n.l_light_mode;
|
||||
return l10n.s_light_mode;
|
||||
case ThemeMode.dark:
|
||||
return l10n.l_dark_mode;
|
||||
return l10n.s_dark_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,7 +114,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.w_settings),
|
||||
title: Text(l10n.s_settings),
|
||||
child: Theme(
|
||||
// Make the headers use the primary color to pop a bit.
|
||||
// Once M3 is implemented this will probably not be needed.
|
||||
@ -127,7 +127,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ListTitle(l10n.l_nfc_options),
|
||||
ListTitle(l10n.s_nfc_options),
|
||||
ListTile(
|
||||
title: Text(l10n.l_on_yk_nfc_tap),
|
||||
subtitle: Text(tapAction.getDescription(l10n)),
|
||||
@ -166,7 +166,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
});
|
||||
}),
|
||||
SwitchListTile(
|
||||
title: Text(l10n.l_silence_nfc_sounds),
|
||||
title: Text(l10n.s_silence_nfc_sounds),
|
||||
subtitle: Text(nfcSilenceSounds
|
||||
? l10n.l_silence_nfc_sounds_on
|
||||
: l10n.l_silence_nfc_sounds_off),
|
||||
@ -177,7 +177,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
prefs.setBool(prefNfcSilenceSounds, value);
|
||||
});
|
||||
}),
|
||||
ListTitle(l10n.l_usb_options),
|
||||
ListTitle(l10n.s_usb_options),
|
||||
SwitchListTile(
|
||||
title: Text(l10n.l_launch_app_on_usb),
|
||||
subtitle: Text(usbOpenApp
|
||||
@ -190,9 +190,9 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
prefs.setBool(prefUsbOpenApp, value);
|
||||
});
|
||||
}),
|
||||
ListTitle(l10n.w_appearance),
|
||||
ListTitle(l10n.s_appearance),
|
||||
ListTile(
|
||||
title: Text(l10n.l_app_theme),
|
||||
title: Text(l10n.s_app_theme),
|
||||
subtitle: Text(themeMode.getDisplayName(l10n)),
|
||||
key: keys.themeModeSetting,
|
||||
onTap: () async {
|
||||
@ -239,7 +239,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
builder: (BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return SimpleDialog(
|
||||
title: Text(l10n.l_choose_kbd_layout),
|
||||
title: Text(l10n.s_choose_kbd_layout),
|
||||
children: _keyboardLayouts
|
||||
.map(
|
||||
(e) => RadioListTile<String>(
|
||||
@ -264,7 +264,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
builder: (BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return SimpleDialog(
|
||||
title: Text(l10n.l_choose_app_theme),
|
||||
title: Text(l10n.s_choose_app_theme),
|
||||
children: supportedThemes
|
||||
.map((e) => RadioListTile(
|
||||
title: Text(e.getDisplayName(l10n)),
|
||||
|
@ -62,9 +62,9 @@ enum Application {
|
||||
String getDisplayName(AppLocalizations l10n) {
|
||||
switch (this) {
|
||||
case Application.oath:
|
||||
return l10n.w_authenticator;
|
||||
return l10n.s_authenticator;
|
||||
case Application.fido:
|
||||
return l10n.w_webauthn;
|
||||
return l10n.s_webauthn;
|
||||
default:
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class AppFailurePage extends ConsumerWidget {
|
||||
case 'ccid':
|
||||
header = l10n.l_ccid_connection_failed;
|
||||
if (Platform.isMacOS) {
|
||||
message = l10n.l_try_reinsert_yk;
|
||||
message = l10n.p_try_reinsert_yk;
|
||||
} else if (Platform.isLinux) {
|
||||
message = l10n.p_pcscd_unavailable;
|
||||
} else {
|
||||
@ -63,7 +63,7 @@ class AppFailurePage extends ConsumerWidget {
|
||||
message = l10n.p_webauthn_elevated_permissions_required;
|
||||
actions = [
|
||||
ElevatedButton.icon(
|
||||
label: Text(l10n.w_unlock),
|
||||
label: Text(l10n.s_unlock),
|
||||
icon: const Icon(Icons.lock_open),
|
||||
onPressed: () async {
|
||||
final closeMessage = showMessage(
|
||||
@ -77,7 +77,7 @@ class AppFailurePage extends ConsumerWidget {
|
||||
(context) async {
|
||||
showMessage(
|
||||
context,
|
||||
l10n.l_permission_denied,
|
||||
l10n.s_permission_denied,
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -92,7 +92,7 @@ class AppFailurePage extends ConsumerWidget {
|
||||
break;
|
||||
default:
|
||||
header = l10n.l_open_connection_failed;
|
||||
message = l10n.l_try_reinsert_yk;
|
||||
message = l10n.p_try_reinsert_yk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ class AppPage extends StatelessWidget {
|
||||
},
|
||||
icon: const Icon(Icons.tune),
|
||||
iconSize: 24,
|
||||
tooltip: AppLocalizations.of(context)!.l_configure_yk,
|
||||
tooltip: AppLocalizations.of(context)!.s_configure_yk,
|
||||
padding: const EdgeInsets.all(12),
|
||||
),
|
||||
),
|
||||
|
@ -45,7 +45,7 @@ class DeviceButton extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return IconButton(
|
||||
tooltip: AppLocalizations.of(context)!.l_select_yk,
|
||||
tooltip: AppLocalizations.of(context)!.s_select_yk,
|
||||
icon: _CircledDeviceAvatar(radius),
|
||||
onPressed: () async {
|
||||
await showBlurDialog(
|
||||
|
@ -44,7 +44,7 @@ class DeviceErrorScreen extends ConsumerWidget {
|
||||
message: l10n.p_elevated_permissions_required,
|
||||
actions: [
|
||||
ElevatedButton.icon(
|
||||
label: Text(l10n.w_unlock),
|
||||
label: Text(l10n.s_unlock),
|
||||
icon: const Icon(Icons.lock_open),
|
||||
onPressed: () async {
|
||||
final closeMessage = showMessage(
|
||||
@ -55,7 +55,7 @@ class DeviceErrorScreen extends ConsumerWidget {
|
||||
ref.invalidate(rpcProvider);
|
||||
} else {
|
||||
await ref.read(withContextProvider)((context) async =>
|
||||
showMessage(context, l10n.l_permission_denied));
|
||||
showMessage(context, l10n.s_permission_denied));
|
||||
}
|
||||
} finally {
|
||||
closeMessage();
|
||||
@ -81,7 +81,7 @@ class DeviceErrorScreen extends ConsumerWidget {
|
||||
final String message;
|
||||
switch (error) {
|
||||
case 'unknown-device':
|
||||
message = l10n.l_unknown_device;
|
||||
message = l10n.s_unknown_device;
|
||||
break;
|
||||
default:
|
||||
message = l10n.l_place_on_nfc_reader;
|
||||
|
@ -122,7 +122,7 @@ class _DevicePickerContent extends ConsumerWidget {
|
||||
title: Center(child: Text(l10n.l_no_yk_present)),
|
||||
subtitle: Center(
|
||||
child: Text(
|
||||
Platform.isAndroid ? l10n.l_insert_or_tap_yk : l10n.w_usb)),
|
||||
Platform.isAndroid ? l10n.l_insert_or_tap_yk : l10n.s_usb)),
|
||||
),
|
||||
],
|
||||
);
|
||||
@ -136,7 +136,7 @@ class _DevicePickerContent extends ConsumerWidget {
|
||||
padding: EdgeInsets.symmetric(horizontal: 4),
|
||||
child: DeviceAvatar(child: Icon(Icons.usb)),
|
||||
),
|
||||
title: Text(l10n.w_usb),
|
||||
title: Text(l10n.s_usb),
|
||||
subtitle: Text(l10n.l_no_yk_present),
|
||||
onTap: () {
|
||||
ref.read(currentDeviceProvider.notifier).setCurrentDevice(null);
|
||||
@ -168,7 +168,7 @@ class _DevicePickerContent extends ConsumerWidget {
|
||||
ref.read(_hiddenDevicesProvider.notifier).showAll();
|
||||
},
|
||||
child: ListTile(
|
||||
title: Text(l10n.l_show_hidden_devices),
|
||||
title: Text(l10n.s_show_hidden_devices),
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
@ -195,11 +195,11 @@ String _getDeviceInfoString(BuildContext context, DeviceInfo info) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final serial = info.serial;
|
||||
return [
|
||||
if (serial != null) l10n.l_sn_serial(serial),
|
||||
if (serial != null) l10n.s_sn_serial(serial),
|
||||
if (info.version.isAtLeast(1))
|
||||
l10n.l_fw_version(info.version)
|
||||
l10n.s_fw_version(info.version)
|
||||
else
|
||||
l10n.l_unknown_type,
|
||||
l10n.s_unknown_type,
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
@ -211,9 +211,9 @@ List<String> _getDeviceStrings(
|
||||
error: (error, _) {
|
||||
switch (error) {
|
||||
case 'device-inaccessible':
|
||||
return [node.name, l10n.l_yk_inaccessible];
|
||||
return [node.name, l10n.s_yk_inaccessible];
|
||||
case 'unknown-device':
|
||||
return [l10n.l_unknown_device];
|
||||
return [l10n.s_unknown_device];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@ -306,9 +306,9 @@ class _DeviceRow extends ConsumerWidget {
|
||||
subtitle: Text(
|
||||
node.when(
|
||||
usbYubiKey: (_, __, ___, info) => info == null
|
||||
? l10n.l_yk_inaccessible
|
||||
? l10n.s_yk_inaccessible
|
||||
: _getDeviceInfoString(context, info),
|
||||
nfcReader: (_, __) => l10n.l_select_to_scan,
|
||||
nfcReader: (_, __) => l10n.s_select_to_scan,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
@ -344,7 +344,7 @@ class _NfcDeviceRow extends ConsumerWidget {
|
||||
ref.read(_hiddenDevicesProvider.notifier).showAll();
|
||||
},
|
||||
child: ListTile(
|
||||
title: Text(l10n.l_show_hidden_devices),
|
||||
title: Text(l10n.s_show_hidden_devices),
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
enabled: hidden.isNotEmpty,
|
||||
@ -355,7 +355,7 @@ class _NfcDeviceRow extends ConsumerWidget {
|
||||
ref.read(_hiddenDevicesProvider.notifier).hideDevice(node.path);
|
||||
},
|
||||
child: ListTile(
|
||||
title: Text(l10n.l_hide_device),
|
||||
title: Text(l10n.s_hide_device),
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
|
@ -142,7 +142,7 @@ class MainPageDrawer extends ConsumerWidget {
|
||||
NavigationDrawerDestination(
|
||||
key: managementAppDrawer,
|
||||
label: Text(
|
||||
l10n.l_toggle_applications,
|
||||
l10n.s_toggle_applications,
|
||||
),
|
||||
icon: Icon(Application.management._icon),
|
||||
selectedIcon: Icon(Application.management._filledIcon),
|
||||
@ -152,11 +152,11 @@ class MainPageDrawer extends ConsumerWidget {
|
||||
],
|
||||
// Non-YubiKey pages
|
||||
NavigationDrawerDestination(
|
||||
label: Text(l10n.w_settings),
|
||||
label: Text(l10n.s_settings),
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
),
|
||||
NavigationDrawerDestination(
|
||||
label: Text(l10n.l_help_and_about),
|
||||
label: Text(l10n.s_help_and_about),
|
||||
icon: const Icon(Icons.help_outline),
|
||||
),
|
||||
],
|
||||
|
@ -88,7 +88,7 @@ class MainPage extends ConsumerWidget {
|
||||
actions: [
|
||||
if (hasNfcSupport && !isNfcEnabled)
|
||||
ElevatedButton.icon(
|
||||
label: Text(l10n.l_enable_nfc),
|
||||
label: Text(l10n.s_enable_nfc),
|
||||
icon: nfcIcon,
|
||||
onPressed: () async {
|
||||
await openNfcSettings();
|
||||
@ -96,7 +96,7 @@ class MainPage extends ConsumerWidget {
|
||||
],
|
||||
actionButtonBuilder: (context) => IconButton(
|
||||
icon: const Icon(Icons.person_add_alt_1),
|
||||
tooltip: l10n.l_add_account,
|
||||
tooltip: l10n.s_add_account,
|
||||
onPressed: () async {
|
||||
CredentialData? otpauth;
|
||||
final scanner = ref.read(qrScannerProvider);
|
||||
@ -142,17 +142,17 @@ class MainPage extends ConsumerWidget {
|
||||
if (data.info.supportedCapabilities.isEmpty &&
|
||||
data.name == 'Unrecognized device') {
|
||||
return MessagePage(
|
||||
header: l10n.l_yk_not_recognized,
|
||||
header: l10n.s_yk_not_recognized,
|
||||
);
|
||||
} else if (app.getAvailability(data) ==
|
||||
Availability.unsupported) {
|
||||
return MessagePage(
|
||||
header: l10n.l_app_not_supported,
|
||||
header: l10n.s_app_not_supported,
|
||||
message: l10n.l_app_not_supported_on_yk(app.name),
|
||||
);
|
||||
} else if (app.getAvailability(data) != Availability.enabled) {
|
||||
return MessagePage(
|
||||
header: l10n.l_app_disabled,
|
||||
header: l10n.s_app_disabled,
|
||||
message: l10n.l_app_disabled_desc(app.name),
|
||||
);
|
||||
}
|
||||
@ -164,7 +164,7 @@ class MainPage extends ConsumerWidget {
|
||||
return FidoScreen(data);
|
||||
default:
|
||||
return MessagePage(
|
||||
header: l10n.l_app_not_supported,
|
||||
header: l10n.s_app_not_supported,
|
||||
message: l10n.l_app_not_supported_desc,
|
||||
);
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ class _HelperWaiterState extends ConsumerState<_HelperWaiter> {
|
||||
actions: [
|
||||
ActionChip(
|
||||
avatar: const Icon(Icons.copy),
|
||||
label: Text(l10n.l_copy_log),
|
||||
label: Text(l10n.s_copy_log),
|
||||
onPressed: () async {
|
||||
_log.info('Copying log to clipboard ($version)...');
|
||||
final logs = await ref.read(logLevelProvider.notifier).getLogs();
|
||||
|
@ -271,7 +271,7 @@ class DesktopCredentialListNotifier extends OathCredentialListNotifier {
|
||||
return promptUserInteraction(
|
||||
context,
|
||||
icon: const Icon(Icons.touch_app),
|
||||
title: l10n.l_touch_required,
|
||||
title: l10n.s_touch_required,
|
||||
description: l10n.l_touch_button_now,
|
||||
headless: headless,
|
||||
);
|
||||
|
@ -176,7 +176,7 @@ class _Systray extends TrayListener {
|
||||
.read(clipboardProvider)
|
||||
.setText(code.value, isSensitive: true);
|
||||
final notification = LocalNotification(
|
||||
title: _l10n.l_code_copied,
|
||||
title: _l10n.s_code_copied,
|
||||
body: _l10n.p_target_copied_clipboard(label),
|
||||
silent: true,
|
||||
);
|
||||
@ -190,12 +190,12 @@ class _Systray extends TrayListener {
|
||||
),
|
||||
if (_credentials.isEmpty)
|
||||
MenuItem(
|
||||
label: _l10n.l_no_pinned_accounts,
|
||||
label: _l10n.s_no_pinned_accounts,
|
||||
disabled: true,
|
||||
),
|
||||
MenuItem.separator(),
|
||||
MenuItem(
|
||||
label: _isHidden ? _l10n.l_show_window : _l10n.l_hide_window,
|
||||
label: _isHidden ? _l10n.s_show_window : _l10n.s_hide_window,
|
||||
onClick: (_) {
|
||||
_ref
|
||||
.read(desktopWindowStateProvider.notifier)
|
||||
@ -204,7 +204,7 @@ class _Systray extends TrayListener {
|
||||
),
|
||||
MenuItem.separator(),
|
||||
MenuItem(
|
||||
label: _l10n.w_quit,
|
||||
label: _l10n.s_quit,
|
||||
onClick: (_) {
|
||||
_ref.read(withContextProvider)(
|
||||
(context) async {
|
||||
|
@ -25,7 +25,7 @@ class ErrorPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(AppLocalizations.of(context)!.l_application_error),
|
||||
title: Text(AppLocalizations.of(context)!.s_application_error),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
|
@ -146,7 +146,7 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
.renameFingerprint(_fingerprint!, _label);
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, l10n.l_fingerprint_added);
|
||||
showMessage(context, l10n.s_fingerprint_added);
|
||||
} catch (e) {
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
@ -169,7 +169,7 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
final progress = _samples == 0 ? 0.0 : _samples / (_samples + _remaining);
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_add_fingerprint),
|
||||
title: Text(l10n.s_add_fingerprint),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Column(
|
||||
@ -208,7 +208,7 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
decoration: InputDecoration(
|
||||
enabled: _fingerprint != null,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.w_name,
|
||||
labelText: l10n.s_name,
|
||||
prefixIcon: const Icon(Icons.fingerprint_outlined),
|
||||
),
|
||||
onChanged: (value) {
|
||||
@ -234,7 +234,7 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: _fingerprint != null && _label.isNotEmpty ? _submit : null,
|
||||
child: Text(l10n.w_save),
|
||||
child: Text(l10n.s_save),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -38,7 +38,7 @@ class DeleteCredentialDialog extends ConsumerWidget {
|
||||
final label = credential.userName;
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_delete_credential),
|
||||
title: Text(l10n.s_delete_credential),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Column(
|
||||
@ -63,11 +63,11 @@ class DeleteCredentialDialog extends ConsumerWidget {
|
||||
await ref.read(withContextProvider)(
|
||||
(context) async {
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, l10n.l_credential_deleted);
|
||||
showMessage(context, l10n.s_credential_deleted);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text(l10n.w_delete),
|
||||
child: Text(l10n.s_delete),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -36,7 +36,7 @@ class DeleteFingerprintDialog extends ConsumerWidget {
|
||||
final label = fingerprint.label;
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_delete_fingerprint),
|
||||
title: Text(l10n.s_delete_fingerprint),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
@ -45,10 +45,10 @@ class DeleteFingerprintDialog extends ConsumerWidget {
|
||||
.deleteFingerprint(fingerprint);
|
||||
await ref.read(withContextProvider)((context) async {
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, l10n.l_fingerprint_deleted);
|
||||
showMessage(context, l10n.s_fingerprint_deleted);
|
||||
});
|
||||
},
|
||||
child: Text(l10n.w_delete),
|
||||
child: Text(l10n.s_delete),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
|
@ -37,7 +37,7 @@ class FidoScreen extends ConsumerWidget {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ref.watch(fidoStateProvider(deviceData.node.path)).when(
|
||||
loading: () => AppPage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
centered: true,
|
||||
delayedContent: true,
|
||||
child: const CircularProgressIndicator(),
|
||||
@ -48,7 +48,7 @@ class FidoScreen extends ConsumerWidget {
|
||||
0;
|
||||
if (Capability.fido2.value & supported == 0) {
|
||||
return MessagePage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
graphic: manageAccounts,
|
||||
header: l10n.l_ready_to_use,
|
||||
message: l10n.l_register_sk_on_websites,
|
||||
@ -59,14 +59,14 @@ class FidoScreen extends ConsumerWidget {
|
||||
0;
|
||||
if (Capability.fido2.value & enabled == 0) {
|
||||
return MessagePage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
header: l10n.l_fido_disabled,
|
||||
title: Text(l10n.s_webauthn),
|
||||
header: l10n.s_fido_disabled,
|
||||
message: l10n.l_webauthn_req_fido2,
|
||||
);
|
||||
}
|
||||
|
||||
return AppFailurePage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
cause: error,
|
||||
);
|
||||
},
|
||||
|
@ -32,11 +32,11 @@ Widget fidoBuildActions(
|
||||
return SimpleDialog(
|
||||
children: [
|
||||
if (state.bioEnroll != null) ...[
|
||||
ListTitle(l10n.w_setup,
|
||||
ListTitle(l10n.s_setup,
|
||||
textStyle: Theme.of(context).textTheme.bodyLarge),
|
||||
ListTile(
|
||||
leading: const CircleAvatar(child: Icon(Icons.fingerprint_outlined)),
|
||||
title: Text(l10n.l_add_fingerprint),
|
||||
title: Text(l10n.s_add_fingerprint),
|
||||
subtitle: state.unlocked
|
||||
? Text(l10n.l_fingerprints_used(fingerprints))
|
||||
: Text(state.hasPin
|
||||
@ -54,13 +54,13 @@ Widget fidoBuildActions(
|
||||
: null,
|
||||
),
|
||||
],
|
||||
ListTitle(l10n.w_manage,
|
||||
ListTitle(l10n.s_manage,
|
||||
textStyle: Theme.of(context).textTheme.bodyLarge),
|
||||
ListTile(
|
||||
leading: const CircleAvatar(child: Icon(Icons.pin_outlined)),
|
||||
title: Text(state.hasPin ? l10n.l_change_pin : l10n.l_set_pin),
|
||||
title: Text(state.hasPin ? l10n.s_change_pin : l10n.s_set_pin),
|
||||
subtitle: Text(state.hasPin
|
||||
? l10n.l_fido_pin_protection
|
||||
? l10n.s_fido_pin_protection
|
||||
: l10n.l_fido_pin_protection_optional),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
@ -75,7 +75,7 @@ Widget fidoBuildActions(
|
||||
backgroundColor: theme.error,
|
||||
child: const Icon(Icons.delete_outline),
|
||||
),
|
||||
title: Text(l10n.l_reset_fido),
|
||||
title: Text(l10n.s_reset_fido),
|
||||
subtitle: Text(l10n.l_factory_reset_this_app),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
|
@ -38,15 +38,15 @@ class FidoLockedPage extends ConsumerWidget {
|
||||
if (!state.hasPin) {
|
||||
if (state.bioEnroll != null) {
|
||||
return MessagePage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
graphic: noFingerprints,
|
||||
header: l10n.l_no_fingerprints,
|
||||
header: l10n.s_no_fingerprints,
|
||||
message: l10n.l_set_pin_fingerprints,
|
||||
keyActionsBuilder: _buildActions,
|
||||
);
|
||||
} else {
|
||||
return MessagePage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
graphic: manageAccounts,
|
||||
header: state.credMgmt
|
||||
? l10n.l_no_discoverable_accounts
|
||||
@ -59,7 +59,7 @@ class FidoLockedPage extends ConsumerWidget {
|
||||
|
||||
if (!state.credMgmt && state.bioEnroll == null) {
|
||||
return MessagePage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
graphic: manageAccounts,
|
||||
header: l10n.l_ready_to_use,
|
||||
message: l10n.l_register_sk_on_websites,
|
||||
@ -68,7 +68,7 @@ class FidoLockedPage extends ConsumerWidget {
|
||||
}
|
||||
|
||||
return AppPage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
keyActionsBuilder: _buildActions,
|
||||
child: Column(
|
||||
children: [
|
||||
@ -148,7 +148,7 @@ class _PinEntryFormState extends ConsumerState<_PinEntryForm> {
|
||||
controller: _pinController,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.w_pin,
|
||||
labelText: l10n.s_pin,
|
||||
helperText: '', // Prevents dialog resizing
|
||||
errorText: _pinIsWrong ? _getErrorText() : null,
|
||||
errorMaxLines: 3,
|
||||
@ -187,7 +187,7 @@ class _PinEntryFormState extends ConsumerState<_PinEntryForm> {
|
||||
minLeadingWidth: 0,
|
||||
trailing: ElevatedButton.icon(
|
||||
icon: const Icon(Icons.lock_open),
|
||||
label: Text(l10n.w_unlock),
|
||||
label: Text(l10n.s_unlock),
|
||||
onPressed:
|
||||
_pinController.text.isNotEmpty && !_blocked ? _submit : null,
|
||||
),
|
||||
|
@ -57,11 +57,11 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
final minPinLength = widget.state.minPinLength;
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(hasPin ? l10n.l_change_pin : l10n.l_set_pin),
|
||||
title: Text(hasPin ? l10n.s_change_pin : l10n.s_set_pin),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: isValid ? _submit : null,
|
||||
child: Text(l10n.w_save),
|
||||
child: Text(l10n.s_save),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
@ -77,7 +77,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_current_pin,
|
||||
labelText: l10n.s_current_pin,
|
||||
errorText: _currentIsWrong ? _currentPinError : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
@ -98,7 +98,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_new_pin,
|
||||
labelText: l10n.s_new_pin,
|
||||
enabled: !hasPin || _currentPin.isNotEmpty,
|
||||
errorText: _newIsWrong ? _newPinError : null,
|
||||
errorMaxLines: 3,
|
||||
@ -116,7 +116,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_confirm_pin,
|
||||
labelText: l10n.s_confirm_pin,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
enabled:
|
||||
(!hasPin || _currentPin.isNotEmpty) && _newPin.isNotEmpty,
|
||||
@ -160,7 +160,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
.setPin(_newPin, oldPin: oldPin);
|
||||
result.when(success: () {
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, l10n.l_pin_set);
|
||||
showMessage(context, l10n.s_pin_set);
|
||||
}, failed: (retries, authBlocked) {
|
||||
setState(() {
|
||||
if (authBlocked) {
|
||||
|
@ -54,7 +54,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
.renameFingerprint(widget.fingerprint, _label);
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop(renamed);
|
||||
showMessage(context, l10n.l_fingerprint_renamed);
|
||||
showMessage(context, l10n.s_fingerprint_renamed);
|
||||
} catch (e) {
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
@ -75,11 +75,11 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_rename_fp),
|
||||
title: Text(l10n.s_rename_fp),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: _label.isNotEmpty ? _submit : null,
|
||||
child: Text(l10n.w_save),
|
||||
child: Text(l10n.s_save),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
@ -96,7 +96,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
buildCounter: buildByteCounterFor(_label),
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.w_label,
|
||||
labelText: l10n.s_label,
|
||||
prefixIcon: const Icon(Icons.fingerprint_outlined),
|
||||
),
|
||||
onChanged: (value) {
|
||||
|
@ -63,7 +63,7 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_factory_reset),
|
||||
title: Text(l10n.s_factory_reset),
|
||||
onCancel: () {
|
||||
_subscription?.cancel();
|
||||
},
|
||||
@ -100,7 +100,7 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
|
||||
});
|
||||
}
|
||||
: null,
|
||||
child: Text(l10n.w_reset),
|
||||
child: Text(l10n.s_reset),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
|
@ -48,7 +48,7 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
}
|
||||
final creds = data.value;
|
||||
if (creds.isNotEmpty) {
|
||||
children.add(ListTitle(l10n.w_credentials));
|
||||
children.add(ListTitle(l10n.s_credentials));
|
||||
children.addAll(
|
||||
creds.map(
|
||||
(cred) => ListTile(
|
||||
@ -96,7 +96,7 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
final fingerprints = data.value;
|
||||
if (fingerprints.isNotEmpty) {
|
||||
nFingerprints = fingerprints.length;
|
||||
children.add(ListTitle(l10n.w_fingerprints));
|
||||
children.add(ListTitle(l10n.s_fingerprints));
|
||||
children.addAll(fingerprints.map((fp) => ListTile(
|
||||
leading: CircleAvatar(
|
||||
foregroundColor: Theme.of(context).colorScheme.onSecondary,
|
||||
@ -137,7 +137,7 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
|
||||
if (children.isNotEmpty) {
|
||||
return AppPage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
keyActionsBuilder: (context) =>
|
||||
fidoBuildActions(context, node, state, nFingerprints),
|
||||
child: Column(
|
||||
@ -147,9 +147,9 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
|
||||
if (state.bioEnroll != null) {
|
||||
return MessagePage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
graphic: noFingerprints,
|
||||
header: l10n.l_no_fingerprints,
|
||||
header: l10n.s_no_fingerprints,
|
||||
message: l10n.l_add_one_or_more_fps,
|
||||
keyActionsBuilder: (context) =>
|
||||
fidoBuildActions(context, node, state, 0),
|
||||
@ -157,7 +157,7 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
}
|
||||
|
||||
return MessagePage(
|
||||
title: Text(l10n.w_webauthn),
|
||||
title: Text(l10n.s_webauthn),
|
||||
graphic: manageAccounts,
|
||||
header: l10n.l_no_discoverable_accounts,
|
||||
message: l10n.l_register_sk_on_websites,
|
||||
@ -166,7 +166,7 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
}
|
||||
|
||||
Widget _buildLoadingPage(BuildContext context) => AppPage(
|
||||
title: Text(AppLocalizations.of(context)!.w_webauthn),
|
||||
title: Text(AppLocalizations.of(context)!.s_webauthn),
|
||||
centered: true,
|
||||
delayedContent: true,
|
||||
child: const CircularProgressIndicator(),
|
||||
|
@ -4,31 +4,37 @@
|
||||
"@_readme": {
|
||||
"notes": [
|
||||
"All strings start with a Captial letter.",
|
||||
"Group strings by category, but don't needlessly tie them to a section of the app if they can be re-used between several."
|
||||
"Group strings by category, but don't needlessly tie them to a section of the app if they can be re-used between several.",
|
||||
"Run check_strings.py on the .arb file to detect problems, tweak @_lint_rules as needed per language."
|
||||
],
|
||||
"prefixes": {
|
||||
"w_": "A single word",
|
||||
"l_": "A single line. Should not be more than one sentence, and not end with a period.",
|
||||
"s_": "A single, or few words. Should be short enough to display on a button, or a header.",
|
||||
"l_": "A single line, can be wrapped. Should not be more than one sentence, and not end with a period.",
|
||||
"p_": "One or more full sentences, with proper punctuation.",
|
||||
"q_": "A question, ending in question mark."
|
||||
}
|
||||
},
|
||||
|
||||
"@_lint_rules": {
|
||||
"s_max_words": 4,
|
||||
"s_max_length": 32
|
||||
},
|
||||
|
||||
"app_name": "Yubico Authenticator",
|
||||
|
||||
"w_save": "Save",
|
||||
"w_cancel": "Cancel",
|
||||
"w_close": "Close",
|
||||
"w_delete": "Delete",
|
||||
"w_quit": "Quit",
|
||||
"w_unlock": "Unlock",
|
||||
"w_calculate": "Calculate",
|
||||
"w_label": "Label",
|
||||
"w_name": "Name",
|
||||
"w_usb": "USB",
|
||||
"w_nfc": "NFC",
|
||||
"l_show_window": "Show window",
|
||||
"l_hide_window": "Hide window",
|
||||
"s_save": "Save",
|
||||
"s_cancel": "Cancel",
|
||||
"s_close": "Close",
|
||||
"s_delete": "Delete",
|
||||
"s_quit": "Quit",
|
||||
"s_unlock": "Unlock",
|
||||
"s_calculate": "Calculate",
|
||||
"s_label": "Label",
|
||||
"s_name": "Name",
|
||||
"s_usb": "USB",
|
||||
"s_nfc": "NFC",
|
||||
"s_show_window": "Show window",
|
||||
"s_hide_window": "Hide window",
|
||||
"q_rename_target": "Rename {label}?",
|
||||
"@q_rename_target" : {
|
||||
"placeholders": {
|
||||
@ -36,62 +42,62 @@
|
||||
}
|
||||
},
|
||||
|
||||
"w_about": "About",
|
||||
"w_appearance": "Appearance",
|
||||
"w_authenticator": "Authenticator",
|
||||
"w_manage": "Manage",
|
||||
"w_setup": "Setup",
|
||||
"w_settings": "Settings",
|
||||
"w_webauthn": "WebAuthn",
|
||||
"l_help_and_about": "Help and about",
|
||||
"l_help_and_feedback": "Help and feedback",
|
||||
"l_send_feedback": "Send us feedback",
|
||||
"l_i_need_help": "I need help",
|
||||
"w_troubleshooting": "Troubleshooting",
|
||||
"l_terms_of_use": "Terms of use",
|
||||
"l_privacy_policy": "Privacy policy",
|
||||
"l_open_src_licenses": "Open source licenses",
|
||||
"l_configure_yk": "Configure YubiKey",
|
||||
"l_please_wait": "Please wait\u2026",
|
||||
"l_secret_key": "Secret key",
|
||||
"l_invalid_length": "Invalid length",
|
||||
"l_require_touch": "Require touch",
|
||||
"s_about": "About",
|
||||
"s_appearance": "Appearance",
|
||||
"s_authenticator": "Authenticator",
|
||||
"s_manage": "Manage",
|
||||
"s_setup": "Setup",
|
||||
"s_settings": "Settings",
|
||||
"s_webauthn": "WebAuthn",
|
||||
"s_help_and_about": "Help and about",
|
||||
"s_help_and_feedback": "Help and feedback",
|
||||
"s_send_feedback": "Send us feedback",
|
||||
"s_i_need_help": "I need help",
|
||||
"s_troubleshooting": "Troubleshooting",
|
||||
"s_terms_of_use": "Terms of use",
|
||||
"s_privacy_policy": "Privacy policy",
|
||||
"s_open_src_licenses": "Open source licenses",
|
||||
"s_configure_yk": "Configure YubiKey",
|
||||
"s_please_wait": "Please wait\u2026",
|
||||
"s_secret_key": "Secret key",
|
||||
"s_invalid_length": "Invalid length",
|
||||
"s_require_touch": "Require touch",
|
||||
"q_have_account_info": "Have account info?",
|
||||
"l_run_diagnostics": "Run diagnostics",
|
||||
"l_log_level": "Log level: {level}",
|
||||
"@l_log_level": {
|
||||
"s_run_diagnostics": "Run diagnostics",
|
||||
"s_log_level": "Log level: {level}",
|
||||
"@s_log_level": {
|
||||
"placeholders": {
|
||||
"level": {}
|
||||
}
|
||||
},
|
||||
"l_character_count": "Character count",
|
||||
"l_learn_more": "Learn\u00a0more",
|
||||
"s_character_count": "Character count",
|
||||
"s_learn_more": "Learn\u00a0more",
|
||||
|
||||
"@_language": {},
|
||||
"w_language": "Language",
|
||||
"s_language": "Language",
|
||||
"l_enable_community_translations": "Enable community translations",
|
||||
"p_community_translations_desc": "These translations are provided and maintained by the community. They may contain errors or be incomplete.",
|
||||
|
||||
"@_theme": {},
|
||||
"l_app_theme": "App theme",
|
||||
"l_choose_app_theme": "Choose app theme",
|
||||
"l_system_default": "System default",
|
||||
"l_light_mode": "Light mode",
|
||||
"l_dark_mode": "Dark mode",
|
||||
"s_app_theme": "App theme",
|
||||
"s_choose_app_theme": "Choose app theme",
|
||||
"s_system_default": "System default",
|
||||
"s_light_mode": "Light mode",
|
||||
"s_dark_mode": "Dark mode",
|
||||
|
||||
"@_yubikey_selection": {},
|
||||
"l_select_yk": "Select YubiKey",
|
||||
"l_select_to_scan": "Select to scan",
|
||||
"l_hide_device": "Hide device",
|
||||
"l_show_hidden_devices": "Show hidden devices",
|
||||
"l_sn_serial": "S/N: {serial}",
|
||||
"@l_sn_serial" : {
|
||||
"s_select_yk": "Select YubiKey",
|
||||
"s_select_to_scan": "Select to scan",
|
||||
"s_hide_device": "Hide device",
|
||||
"s_show_hidden_devices": "Show hidden devices",
|
||||
"s_sn_serial": "S/N: {serial}",
|
||||
"@s_sn_serial" : {
|
||||
"placeholders": {
|
||||
"serial": {}
|
||||
}
|
||||
},
|
||||
"l_fw_version": "F/W: {version}",
|
||||
"@l_fw_version" : {
|
||||
"s_fw_version": "F/W: {version}",
|
||||
"@s_fw_version" : {
|
||||
"placeholders": {
|
||||
"version": {}
|
||||
}
|
||||
@ -105,18 +111,18 @@
|
||||
"l_place_on_nfc_reader": "Place your YubiKey on the NFC reader",
|
||||
"l_replace_yk_on_reader": "Place your YubiKey back on the reader",
|
||||
"l_remove_yk_from_reader": "Remove your YubiKey from the NFC reader",
|
||||
"l_try_reinsert_yk": "Try to remove and reinsert your YubiKey.",
|
||||
"l_touch_required": "Touch required",
|
||||
"p_try_reinsert_yk": "Try to remove and reinsert your YubiKey.",
|
||||
"s_touch_required": "Touch required",
|
||||
"l_touch_button_now": "Touch the button on your YubiKey now",
|
||||
"l_keep_touching_yk": "Keep touching your YubiKey repeatedly\u2026",
|
||||
|
||||
"@_app_configuration": {},
|
||||
"l_toggle_applications": "Toggle applications",
|
||||
"s_toggle_applications": "Toggle applications",
|
||||
"l_min_one_interface": "At least one interface must be enabled",
|
||||
"l_reconfiguring_yk": "Reconfiguring YubiKey\u2026",
|
||||
"l_config_updated": "Configuration updated",
|
||||
"s_reconfiguring_yk": "Reconfiguring YubiKey\u2026",
|
||||
"s_config_updated": "Configuration updated",
|
||||
"l_config_updated_reinsert": "Configuration updated, remove and reinsert your YubiKey",
|
||||
"l_app_not_supported": "Application not supported",
|
||||
"s_app_not_supported": "Application not supported",
|
||||
"l_app_not_supported_on_yk": "The used YubiKey does not support '${app}' application",
|
||||
"@l_app_not_supported_on_yk" : {
|
||||
"placeholders": {
|
||||
@ -124,65 +130,65 @@
|
||||
}
|
||||
},
|
||||
"l_app_not_supported_desc": "This application is not supported",
|
||||
"l_app_disabled": "Application disabled",
|
||||
"s_app_disabled": "Application disabled",
|
||||
"l_app_disabled_desc": "Enable the '{app}' application on your YubiKey to access",
|
||||
"@l_app_disabled_desc" : {
|
||||
"placeholders": {
|
||||
"app": {}
|
||||
}
|
||||
},
|
||||
"l_fido_disabled": "FIDO2 disabled",
|
||||
"s_fido_disabled": "FIDO2 disabled",
|
||||
"l_webauthn_req_fido2": "WebAuthn requires the FIDO2 application to be enabled on your YubiKey",
|
||||
|
||||
"@_connectivity_issues": {},
|
||||
"l_helper_not_responding": "The Helper process isn't responding",
|
||||
"l_yk_no_access": "This YubiKey cannot be accessed",
|
||||
"l_yk_inaccessible": "Device inaccessible",
|
||||
"s_yk_inaccessible": "Device inaccessible",
|
||||
"l_open_connection_failed": "Failed to open connection",
|
||||
"l_ccid_connection_failed": "Failed to open smart card connection",
|
||||
"p_ccid_service_unavailable": "Make sure your smart card service is functioning.",
|
||||
"p_pcscd_unavailable": "Make sure pcscd is installed and running.",
|
||||
"l_no_yk_present": "No YubiKey present",
|
||||
"l_unknown_type": "Unknown type",
|
||||
"l_unknown_device": "Unrecognized device",
|
||||
"l_unsupported_yk": "Unsupported YubiKey",
|
||||
"l_yk_not_recognized": "Device not recognized",
|
||||
"s_unknown_type": "Unknown type",
|
||||
"s_unknown_device": "Unrecognized device",
|
||||
"s_unsupported_yk": "Unsupported YubiKey",
|
||||
"s_yk_not_recognized": "Device not recognized",
|
||||
|
||||
"@_general_errors": {},
|
||||
"l_error_occured": "An error has occured",
|
||||
"l_application_error": "Application error",
|
||||
"s_application_error": "Application error",
|
||||
"l_import_error": "Import error",
|
||||
"l_file_not_found": "File not found",
|
||||
"l_file_too_big": "File size too big",
|
||||
"l_filesystem_error": "File system operation error",
|
||||
|
||||
"@_pins": {},
|
||||
"w_pin": "PIN",
|
||||
"l_set_pin": "Set PIN",
|
||||
"l_change_pin": "Change PIN",
|
||||
"l_current_pin": "Current PIN",
|
||||
"l_new_pin": "New PIN",
|
||||
"l_confirm_pin": "Confirm PIN",
|
||||
"s_pin": "PIN",
|
||||
"s_set_pin": "Set PIN",
|
||||
"s_change_pin": "Change PIN",
|
||||
"s_current_pin": "Current PIN",
|
||||
"s_new_pin": "New PIN",
|
||||
"s_confirm_pin": "Confirm PIN",
|
||||
"l_new_pin_len": "New PIN must be at least {length} characters",
|
||||
"@l_new_pin_len" : {
|
||||
"placeholders": {
|
||||
"length": {}
|
||||
}
|
||||
},
|
||||
"l_pin_set": "PIN set",
|
||||
"s_pin_set": "PIN set",
|
||||
"l_set_pin_failed": "Failed to set PIN: {message}",
|
||||
"@l_set_pin_failed" : {
|
||||
"placeholders": {
|
||||
"message": {}
|
||||
}
|
||||
},
|
||||
"l_wrong_pin_attempts_remaining": "Wrong PIN. {retries} attempt(s) remaining.",
|
||||
"l_wrong_pin_attempts_remaining": "Wrong PIN, {retries} attempt(s) remaining",
|
||||
"@l_wrong_pin_attempts_remaining" : {
|
||||
"placeholders": {
|
||||
"retries": {}
|
||||
}
|
||||
},
|
||||
"l_fido_pin_protection": "FIDO PIN protection",
|
||||
"s_fido_pin_protection": "FIDO PIN protection",
|
||||
"l_fido_pin_protection_optional": "Optional FIDO PIN protection",
|
||||
"l_enter_fido2_pin": "Enter the FIDO2 PIN for your YubiKey",
|
||||
"l_optionally_set_a_pin": "Optionally set a PIN to protect access to your YubiKey\nRegister as a Security Key on websites",
|
||||
@ -199,20 +205,20 @@
|
||||
},
|
||||
|
||||
"@_passwords": {},
|
||||
"w_password": "Password",
|
||||
"l_manage_password": "Manage password",
|
||||
"l_set_password": "Set password",
|
||||
"l_password_set": "Password set",
|
||||
"s_password": "Password",
|
||||
"s_manage_password": "Manage password",
|
||||
"s_set_password": "Set password",
|
||||
"s_password_set": "Password set",
|
||||
"l_optional_password_protection": "Optional password protection",
|
||||
"l_new_password": "New password",
|
||||
"l_current_password": "Current password",
|
||||
"l_confirm_password": "Confirm password",
|
||||
"l_wrong_password": "Wrong password",
|
||||
"l_remove_password": "Remove password",
|
||||
"l_password_removed": "Password removed",
|
||||
"l_remember_password": "Remember password",
|
||||
"l_clear_saved_password": "Clear saved password",
|
||||
"l_password_forgotten": "Password forgotten",
|
||||
"s_new_password": "New password",
|
||||
"s_current_password": "Current password",
|
||||
"s_confirm_password": "Confirm password",
|
||||
"s_wrong_password": "Wrong password",
|
||||
"s_remove_password": "Remove password",
|
||||
"s_password_removed": "Password removed",
|
||||
"s_remember_password": "Remember password",
|
||||
"s_clear_saved_password": "Clear saved password",
|
||||
"s_password_forgotten": "Password forgotten",
|
||||
"l_keystore_unavailable": "OS Keystore unavailable",
|
||||
"l_remember_pw_failed": "Failed to remember password",
|
||||
"l_unlock_first": "Unlock with password first",
|
||||
@ -227,10 +233,10 @@
|
||||
"label": {}
|
||||
}
|
||||
},
|
||||
"w_accounts": "Accounts",
|
||||
"l_no_accounts": "No accounts",
|
||||
"l_add_account": "Add account",
|
||||
"l_account_added": "Account added",
|
||||
"s_accounts": "Accounts",
|
||||
"s_no_accounts": "No accounts",
|
||||
"s_add_account": "Add account",
|
||||
"s_account_added": "Account added",
|
||||
"l_account_add_failed": "Failed adding account: {message}",
|
||||
"@l_account_add_failed" : {
|
||||
"placeholders": {
|
||||
@ -240,19 +246,19 @@
|
||||
"l_account_name_required": "Your account must have a name",
|
||||
"l_name_already_exists": "This name already exists for the issuer",
|
||||
"l_invalid_character_issuer": "Invalid character: ':' is not allowed in issuer",
|
||||
"w_pinned": "Pinned",
|
||||
"l_pin_account": "Pin account",
|
||||
"l_unpin_account": "Unpin account",
|
||||
"l_no_pinned_accounts": "No pinned accounts",
|
||||
"l_rename_account": "Rename account",
|
||||
"l_account_renamed": "Account renamed",
|
||||
"s_pinned": "Pinned",
|
||||
"s_pin_account": "Pin account",
|
||||
"s_unpin_account": "Unpin account",
|
||||
"s_no_pinned_accounts": "No pinned accounts",
|
||||
"s_rename_account": "Rename account",
|
||||
"s_account_renamed": "Account renamed",
|
||||
"p_rename_will_change_account_displayed": "This will change how the account is displayed in the list.",
|
||||
"l_delete_account": "Delete account",
|
||||
"l_account_deleted": "Account deleted",
|
||||
"s_delete_account": "Delete account",
|
||||
"s_account_deleted": "Account deleted",
|
||||
"p_warning_delete_account": "Warning! This action will delete the account from your YubiKey.",
|
||||
"p_warning_disable_credential": "You will no longer be able to generate OTPs for this account. Make sure to first disable this credential from the website to avoid being locked out of your account.",
|
||||
"l_account_name": "Account name",
|
||||
"l_search_accounts": "Search accounts",
|
||||
"s_account_name": "Account name",
|
||||
"s_search_accounts": "Search accounts",
|
||||
"l_accounts_used": "{used} of {capacity} accounts used",
|
||||
"@l_accounts_used" : {
|
||||
"placeholders": {
|
||||
@ -260,19 +266,19 @@
|
||||
"capacity": {}
|
||||
}
|
||||
},
|
||||
"l_num_digits": "{num} digits",
|
||||
"@l_num_digits" : {
|
||||
"s_num_digits": "{num} digits",
|
||||
"@s_num_digits" : {
|
||||
"placeholders": {
|
||||
"num": {}
|
||||
}
|
||||
},
|
||||
"l_num_sec": "{num} sec",
|
||||
"@l_num_sec" : {
|
||||
"s_num_sec": "{num} sec",
|
||||
"@s_num_sec" : {
|
||||
"placeholders": {
|
||||
"num": {}
|
||||
}
|
||||
},
|
||||
"l_issuer_optional": "Issuer (optional)",
|
||||
"s_issuer_optional": "Issuer (optional)",
|
||||
|
||||
"@_fido_credentials": {},
|
||||
"l_credential": "Credential: {label}",
|
||||
@ -281,12 +287,12 @@
|
||||
"label": {}
|
||||
}
|
||||
},
|
||||
"w_credentials": "Credentials",
|
||||
"s_credentials": "Credentials",
|
||||
"l_ready_to_use": "Ready to use",
|
||||
"l_register_sk_on_websites": "Register as a Security Key on websites",
|
||||
"l_no_discoverable_accounts": "No discoverable accounts",
|
||||
"l_delete_credential": "Delete credential",
|
||||
"l_credential_deleted": "Credential deleted",
|
||||
"s_delete_credential": "Delete credential",
|
||||
"s_credential_deleted": "Credential deleted",
|
||||
"p_warning_delete_credential": "This will delete the credential from your YubiKey.",
|
||||
|
||||
"@_fingerprints": {},
|
||||
@ -296,32 +302,32 @@
|
||||
"label": {}
|
||||
}
|
||||
},
|
||||
"w_fingerprints": "Fingerprints",
|
||||
"s_fingerprints": "Fingerprints",
|
||||
"l_fingerprint_captured": "Fingerprint captured successfully!",
|
||||
"l_fingerprint_added": "Fingerprint added",
|
||||
"s_fingerprint_added": "Fingerprint added",
|
||||
"l_setting_name_failed": "Error setting name: {message}",
|
||||
"@l_setting_name_failed" : {
|
||||
"placeholders": {
|
||||
"message": {}
|
||||
}
|
||||
},
|
||||
"l_add_fingerprint": "Add fingerprint",
|
||||
"s_add_fingerprint": "Add fingerprint",
|
||||
"l_fp_step_1_capture": "Step 1/2: Capture fingerprint",
|
||||
"l_fp_step_2_name": "Step 2/2: Name fingerprint",
|
||||
"l_delete_fingerprint": "Delete fingerprint",
|
||||
"l_fingerprint_deleted": "Fingerprint deleted",
|
||||
"s_delete_fingerprint": "Delete fingerprint",
|
||||
"s_fingerprint_deleted": "Fingerprint deleted",
|
||||
"p_warning_delete_fingerprint": "This will delete the fingerprint from your YubiKey.",
|
||||
"l_no_fingerprints": "No fingerprints",
|
||||
"s_no_fingerprints": "No fingerprints",
|
||||
"l_set_pin_fingerprints": "Set a PIN to register fingerprints",
|
||||
"l_no_fps_added": "No fingerprints have been added",
|
||||
"l_fingerprint_renamed": "Fingerprint renamed",
|
||||
"s_rename_fp": "Rename fingerprint",
|
||||
"s_fingerprint_renamed": "Fingerprint renamed",
|
||||
"l_rename_fp_failed": "Error renaming: {message}",
|
||||
"@l_rename_fp_failed" : {
|
||||
"placeholders": {
|
||||
"message": {}
|
||||
}
|
||||
},
|
||||
"l_rename_fp": "Rename fingerprint",
|
||||
"l_add_one_or_more_fps": "Add one or more (up to five) fingerprints",
|
||||
"l_fingerprints_used": "{used}/5 fingerprints registered",
|
||||
"@l_fingerprints_used": {
|
||||
@ -333,16 +339,16 @@
|
||||
"p_will_change_label_fp": "This will change the label of the fingerprint.",
|
||||
|
||||
"@_permissions": {},
|
||||
"l_enable_nfc": "Enable NFC",
|
||||
"l_permission_denied": "Permission denied",
|
||||
"s_enable_nfc": "Enable NFC",
|
||||
"s_permission_denied": "Permission denied",
|
||||
"l_elevating_permissions": "Elevating permissions\u2026",
|
||||
"l_review_permissions": "Review permissions",
|
||||
"s_review_permissions": "Review permissions",
|
||||
"p_elevated_permissions_required": "Managing this device requires elevated privileges.",
|
||||
"p_webauthn_elevated_permissions_required": "WebAuthn management requires elevated privileges.",
|
||||
"p_need_camera_permission": "Yubico Authenticator needs Camera permissions for scanning QR codes.",
|
||||
|
||||
"@_qr_codes": {},
|
||||
"l_qr_scan": "Scan QR code",
|
||||
"s_qr_scan": "Scan QR code",
|
||||
"l_qr_scanned": "Scanned QR code",
|
||||
"l_invalid_qr": "Invalid QR code",
|
||||
"l_qr_not_found": "No QR code found",
|
||||
@ -355,15 +361,15 @@
|
||||
"l_point_camera_scan": "Point your camera at a QR code to scan it",
|
||||
"q_want_to_scan": "Would like to scan?",
|
||||
"q_no_qr": "No QR code?",
|
||||
"l_enter_manually": "Enter manually",
|
||||
"s_enter_manually": "Enter manually",
|
||||
|
||||
"@_factory_reset": {},
|
||||
"w_reset": "Reset",
|
||||
"l_factory_reset": "Factory reset",
|
||||
"s_reset": "Reset",
|
||||
"s_factory_reset": "Factory reset",
|
||||
"l_factory_reset_this_app": "Factory reset this application",
|
||||
"l_reset_oath": "Reset OATH",
|
||||
"s_reset_oath": "Reset OATH",
|
||||
"l_oath_application_reset": "OATH application reset",
|
||||
"l_reset_fido": "Reset FIDO",
|
||||
"s_reset_fido": "Reset FIDO",
|
||||
"l_fido_app_reset": "FIDO application reset",
|
||||
"l_press_reset_to_begin": "Press reset to begin\u2026",
|
||||
"l_reset_failed": "Error performing reset: {message}",
|
||||
@ -379,9 +385,9 @@
|
||||
|
||||
"@_copy_to_clipboard": {},
|
||||
"l_copy_to_clipboard": "Copy to clipboard",
|
||||
"l_code_copied": "Code copied",
|
||||
"s_code_copied": "Code copied",
|
||||
"l_code_copied_clipboard": "Code copied to clipboard",
|
||||
"l_copy_log": "Copy log",
|
||||
"s_copy_log": "Copy log",
|
||||
"l_log_copied": "Log copied to clipboard",
|
||||
"l_diagnostics_copied": "Diagnostic data copied to clipboard",
|
||||
"p_target_copied_clipboard": "{label} copied to clipboard.",
|
||||
@ -392,16 +398,16 @@
|
||||
},
|
||||
|
||||
"@_custom_icons": {},
|
||||
"l_custom_icons": "Custom icons",
|
||||
"s_custom_icons": "Custom icons",
|
||||
"l_set_icons_for_accounts": "Set icons for accounts",
|
||||
"p_custom_icons_description": "Icon packs can make your accounts more easily distinguishable with familiar logos and colors.",
|
||||
"l_replace_icon_pack": "Replace icon pack",
|
||||
"s_replace_icon_pack": "Replace icon pack",
|
||||
"l_loading_icon_pack": "Loading icon pack\u2026",
|
||||
"l_load_icon_pack": "Load icon pack",
|
||||
"l_remove_icon_pack": "Remove icon pack",
|
||||
"s_load_icon_pack": "Load icon pack",
|
||||
"s_remove_icon_pack": "Remove icon pack",
|
||||
"l_icon_pack_removed": "Icon pack removed",
|
||||
"l_remove_icon_pack_failed": "Error removing icon pack",
|
||||
"l_choose_icon_pack": "Choose icon pack",
|
||||
"s_choose_icon_pack": "Choose icon pack",
|
||||
"l_icon_pack_imported": "Icon pack imported",
|
||||
"l_import_icon_pack_failed": "Error importing icon pack: {message}",
|
||||
"@l_import_icon_pack_failed": {
|
||||
@ -412,24 +418,24 @@
|
||||
"l_invalid_icon_pack": "Invalid icon pack",
|
||||
|
||||
"@_android_settings": {},
|
||||
"l_nfc_options": "NFC options",
|
||||
"s_nfc_options": "NFC options",
|
||||
"l_on_yk_nfc_tap": "On YubiKey NFC tap",
|
||||
"l_launch_ya": "Launch Yubico Authenticator",
|
||||
"l_copy_otp_clipboard": "Copy OTP to clipboard",
|
||||
"l_launch_and_copy_otp": "Launch app and copy OTP",
|
||||
"l_kbd_layout_for_static": "Keyboard layout (for static password)",
|
||||
"l_choose_kbd_layout": "Choose keyboard layout",
|
||||
"s_choose_kbd_layout": "Choose keyboard layout",
|
||||
"l_bypass_touch_requirement": "Bypass touch requirement",
|
||||
"l_bypass_touch_requirement_on": "Accounts that require touch are automatically shown over NFC",
|
||||
"l_bypass_touch_requirement_off": "Accounts that require touch need an additional tap over NFC",
|
||||
"l_silence_nfc_sounds": "Silence NFC sounds",
|
||||
"s_silence_nfc_sounds": "Silence NFC sounds",
|
||||
"l_silence_nfc_sounds_on": "No sounds will be played on NFC tap",
|
||||
"l_silence_nfc_sounds_off": "Sound will play on NFC tap",
|
||||
"l_usb_options": "USB options",
|
||||
"s_usb_options": "USB options",
|
||||
"l_launch_app_on_usb": "Launch when YubiKey is connected",
|
||||
"l_launch_app_on_usb_on": "This prevents other apps from using the YubiKey over USB",
|
||||
"l_launch_app_on_usb_off": "Other apps can use the YubiKey over USB",
|
||||
"l_allow_screenshots": "Allow screenshots",
|
||||
"s_allow_screenshots": "Allow screenshots",
|
||||
|
||||
"@_eof": {}
|
||||
}
|
@ -116,7 +116,7 @@ class _CapabilitiesForm extends StatelessWidget {
|
||||
if (usbCapabilities != 0) ...[
|
||||
ListTile(
|
||||
leading: const Icon(Icons.usb),
|
||||
title: Text(l10n.w_usb),
|
||||
title: Text(l10n.s_usb),
|
||||
contentPadding: const EdgeInsets.only(bottom: 8),
|
||||
horizontalTitleGap: 0,
|
||||
),
|
||||
@ -137,7 +137,7 @@ class _CapabilitiesForm extends StatelessWidget {
|
||||
),
|
||||
ListTile(
|
||||
leading: nfcIcon,
|
||||
title: Text(l10n.w_nfc),
|
||||
title: Text(l10n.s_nfc),
|
||||
contentPadding: const EdgeInsets.only(bottom: 8),
|
||||
horizontalTitleGap: 0,
|
||||
),
|
||||
@ -212,7 +212,7 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
|
||||
// This will take longer, show a message
|
||||
close = showMessage(
|
||||
context,
|
||||
l10n.l_reconfiguring_yk,
|
||||
l10n.s_reconfiguring_yk,
|
||||
duration: const Duration(seconds: 8),
|
||||
);
|
||||
}
|
||||
@ -225,7 +225,7 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
|
||||
);
|
||||
if (!mounted) return;
|
||||
if (!reboot) Navigator.pop(context);
|
||||
showMessage(context, l10n.l_config_updated);
|
||||
showMessage(context, l10n.s_config_updated);
|
||||
} finally {
|
||||
close?.call();
|
||||
}
|
||||
@ -250,7 +250,7 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
|
||||
showMessage(
|
||||
context,
|
||||
widget.deviceData.node.maybeMap(
|
||||
nfcReader: (_) => l10n.l_config_updated,
|
||||
nfcReader: (_) => l10n.s_config_updated,
|
||||
orElse: () => l10n.l_config_updated_reinsert));
|
||||
Navigator.pop(context);
|
||||
}
|
||||
@ -318,12 +318,12 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
|
||||
);
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_toggle_applications),
|
||||
title: Text(l10n.s_toggle_applications),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: canSave ? _submitForm : null,
|
||||
key: management_keys.saveButtonKey,
|
||||
child: Text(l10n.w_save),
|
||||
child: Text(l10n.s_save),
|
||||
),
|
||||
],
|
||||
child: child,
|
||||
|
@ -34,7 +34,7 @@ class IconPackDialog extends ConsumerWidget {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final iconPack = ref.watch(iconPackProvider);
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_custom_icons),
|
||||
title: Text(l10n.s_custom_icons),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Column(
|
||||
@ -66,9 +66,9 @@ class IconPackDialog extends ConsumerWidget {
|
||||
Widget? _action(AsyncValue<IconPack?> iconPack, AppLocalizations l10n) =>
|
||||
iconPack.when(
|
||||
data: (IconPack? data) => _ImportActionChip(
|
||||
data != null ? l10n.l_replace_icon_pack : l10n.l_load_icon_pack),
|
||||
data != null ? l10n.s_replace_icon_pack : l10n.s_load_icon_pack),
|
||||
error: (Object error, StackTrace stackTrace) =>
|
||||
_ImportActionChip(l10n.l_load_icon_pack),
|
||||
_ImportActionChip(l10n.s_load_icon_pack),
|
||||
loading: () => _ImportActionChip(
|
||||
l10n.l_loading_icon_pack,
|
||||
avatar: const CircularProgressIndicator(),
|
||||
@ -96,7 +96,7 @@ class _DialogDescription extends ConsumerWidget {
|
||||
TextSpan _createLearnMoreLink(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return TextSpan(
|
||||
text: AppLocalizations.of(context)!.l_learn_more,
|
||||
text: AppLocalizations.of(context)!.s_learn_more,
|
||||
style: theme.textTheme.bodyMedium
|
||||
?.copyWith(color: theme.colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()
|
||||
@ -134,7 +134,7 @@ class _IconPackDescription extends ConsumerWidget {
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
tooltip: l10n.l_remove_icon_pack,
|
||||
tooltip: l10n.s_remove_icon_pack,
|
||||
onPressed: () async {
|
||||
final removePackStatus =
|
||||
await ref.read(iconPackProvider.notifier).removePack();
|
||||
@ -179,7 +179,7 @@ class _ImportActionChip extends ConsumerWidget {
|
||||
type: FileType.custom,
|
||||
allowMultiple: false,
|
||||
lockParentWindow: true,
|
||||
dialogTitle: l10n.l_choose_icon_pack);
|
||||
dialogTitle: l10n.s_choose_icon_pack);
|
||||
if (result != null && result.files.isNotEmpty) {
|
||||
final importStatus = await ref
|
||||
.read(iconPackProvider.notifier)
|
||||
|
@ -46,7 +46,7 @@ class AccountDialog extends ConsumerWidget {
|
||||
|
||||
final copy =
|
||||
actions.firstWhere(((e) => e.text == l10n.l_copy_to_clipboard));
|
||||
final delete = actions.firstWhere(((e) => e.text == l10n.l_delete_account));
|
||||
final delete = actions.firstWhere(((e) => e.text == l10n.s_delete_account));
|
||||
final colors = {
|
||||
copy: Pair(theme.primary, theme.onPrimary),
|
||||
delete: Pair(theme.error, theme.onError),
|
||||
@ -54,7 +54,7 @@ class AccountDialog extends ConsumerWidget {
|
||||
|
||||
// If we can't copy, but can calculate, highlight that button instead
|
||||
if (copy.intent == null) {
|
||||
final calculates = actions.where(((e) => e.text == l10n.w_calculate));
|
||||
final calculates = actions.where(((e) => e.text == l10n.s_calculate));
|
||||
if (calculates.isNotEmpty) {
|
||||
colors[calculates.first] = Pair(theme.primary, theme.onPrimary);
|
||||
}
|
||||
|
@ -73,12 +73,12 @@ class AccountHelper {
|
||||
),
|
||||
if (manual)
|
||||
MenuAction(
|
||||
text: l10n.w_calculate,
|
||||
text: l10n.s_calculate,
|
||||
icon: const Icon(Icons.refresh),
|
||||
intent: ready ? const CalculateIntent() : null,
|
||||
),
|
||||
MenuAction(
|
||||
text: pinned ? l10n.l_unpin_account : l10n.l_pin_account,
|
||||
text: pinned ? l10n.s_unpin_account : l10n.s_pin_account,
|
||||
icon: pinned
|
||||
? pushPinStrokeIcon
|
||||
: const Icon(Icons.push_pin_outlined),
|
||||
@ -87,11 +87,11 @@ class AccountHelper {
|
||||
if (data.info.version.isAtLeast(5, 3))
|
||||
MenuAction(
|
||||
icon: const Icon(Icons.edit_outlined),
|
||||
text: l10n.l_rename_account,
|
||||
text: l10n.s_rename_account,
|
||||
intent: const EditIntent(),
|
||||
),
|
||||
MenuAction(
|
||||
text: l10n.l_delete_account,
|
||||
text: l10n.s_delete_account,
|
||||
icon: const Icon(Icons.delete_outline),
|
||||
intent: const DeleteIntent(),
|
||||
),
|
||||
|
@ -34,7 +34,7 @@ class AccountList extends ConsumerWidget {
|
||||
final favorites = ref.watch(favoritesProvider);
|
||||
if (credentials.isEmpty) {
|
||||
return Center(
|
||||
child: Text(l10n.l_no_accounts),
|
||||
child: Text(l10n.s_no_accounts),
|
||||
);
|
||||
}
|
||||
|
||||
@ -47,13 +47,13 @@ class AccountList extends ConsumerWidget {
|
||||
policy: WidgetOrderTraversalPolicy(),
|
||||
child: Column(
|
||||
children: [
|
||||
if (pinnedCreds.isNotEmpty) ListTitle(l10n.w_pinned),
|
||||
if (pinnedCreds.isNotEmpty) ListTitle(l10n.s_pinned),
|
||||
...pinnedCreds.map(
|
||||
(entry) => AccountView(
|
||||
entry.credential,
|
||||
),
|
||||
),
|
||||
if (creds.isNotEmpty) ListTitle(l10n.w_accounts),
|
||||
if (creds.isNotEmpty) ListTitle(l10n.s_accounts),
|
||||
...creds.map(
|
||||
(entry) => AccountView(
|
||||
entry.credential,
|
||||
|
@ -188,7 +188,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
}
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
showMessage(context, l10n.l_account_added);
|
||||
showMessage(context, l10n.s_account_added);
|
||||
} on CancellationException catch (_) {
|
||||
// ignored
|
||||
} catch (e) {
|
||||
@ -244,7 +244,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
0) !=
|
||||
0) {
|
||||
if (oathState == null) {
|
||||
_promptController?.updateContent(title: l10n.l_please_wait);
|
||||
_promptController?.updateContent(title: l10n.s_please_wait);
|
||||
} else if (oathState.locked) {
|
||||
_promptController?.close();
|
||||
} else {
|
||||
@ -256,12 +256,12 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
));
|
||||
}
|
||||
} else {
|
||||
_promptController?.updateContent(title: l10n.l_unsupported_yk);
|
||||
_promptController?.updateContent(title: l10n.s_unsupported_yk);
|
||||
}
|
||||
}, error: (error, _) {
|
||||
_promptController?.updateContent(title: l10n.l_unsupported_yk);
|
||||
_promptController?.updateContent(title: l10n.s_unsupported_yk);
|
||||
}, loading: () {
|
||||
_promptController?.updateContent(title: l10n.l_please_wait);
|
||||
_promptController?.updateContent(title: l10n.s_please_wait);
|
||||
});
|
||||
}
|
||||
|
||||
@ -343,7 +343,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
_promptController = promptUserInteraction(
|
||||
context,
|
||||
title: l10n.l_insert_yk,
|
||||
description: l10n.l_add_account,
|
||||
description: l10n.s_add_account,
|
||||
icon: const Icon(Icons.usb),
|
||||
onCancel: () {
|
||||
_otpauthUri = null;
|
||||
@ -358,11 +358,11 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
}
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_add_account),
|
||||
title: Text(l10n.s_add_account),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: isValid ? submit : null,
|
||||
child: Text(l10n.w_save, key: keys.saveButton),
|
||||
child: Text(l10n.s_save, key: keys.saveButton),
|
||||
),
|
||||
],
|
||||
child: FileDropTarget(
|
||||
@ -402,7 +402,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
buildCounter: buildByteCounterFor(issuerText),
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_issuer_optional,
|
||||
labelText: l10n.s_issuer_optional,
|
||||
helperText:
|
||||
'', // Prevents dialog resizing when disabled
|
||||
prefixIcon: const Icon(Icons.business_outlined),
|
||||
@ -431,7 +431,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
prefixIcon: const Icon(Icons.person_outline),
|
||||
labelText: l10n.l_account_name,
|
||||
labelText: l10n.s_account_name,
|
||||
helperText:
|
||||
'', // Prevents dialog resizing when disabled
|
||||
errorText: (byteLength(nameText) > nameMaxLength)
|
||||
@ -474,9 +474,9 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
labelText: l10n.l_secret_key,
|
||||
labelText: l10n.s_secret_key,
|
||||
errorText: _validateSecretLength && !secretLengthValid
|
||||
? l10n.l_invalid_length
|
||||
? l10n.s_invalid_length
|
||||
: null),
|
||||
readOnly: _qrState == _QrScanState.success,
|
||||
textInputAction: TextInputAction.done,
|
||||
@ -502,7 +502,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
strokeWidth: 2.0),
|
||||
label: _qrState == _QrScanState.success
|
||||
? Text(l10n.l_qr_scanned)
|
||||
: Text(l10n.l_qr_scan),
|
||||
: Text(l10n.s_qr_scan),
|
||||
onPressed: () {
|
||||
_scanQrCode(qrScanner);
|
||||
}),
|
||||
@ -515,7 +515,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
children: [
|
||||
if (oathState?.version.isAtLeast(4, 2) ?? true)
|
||||
FilterChip(
|
||||
label: Text(l10n.l_require_touch),
|
||||
label: Text(l10n.s_require_touch),
|
||||
selected: _touch,
|
||||
onSelected: (value) {
|
||||
setState(() {
|
||||
@ -557,7 +557,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
selected: int.tryParse(_periodController.text) !=
|
||||
defaultPeriod,
|
||||
itemBuilder: ((value) =>
|
||||
Text(l10n.l_num_sec(value))),
|
||||
Text(l10n.s_num_sec(value))),
|
||||
onChanged: _qrState != _QrScanState.success
|
||||
? (period) {
|
||||
setState(() {
|
||||
@ -571,7 +571,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
value: _digits,
|
||||
selected: _digits != defaultDigits,
|
||||
itemBuilder: (value) =>
|
||||
Text(l10n.l_num_digits(value)),
|
||||
Text(l10n.s_num_digits(value)),
|
||||
onChanged: _qrState != _QrScanState.success
|
||||
? (digits) {
|
||||
setState(() {
|
||||
|
@ -37,7 +37,7 @@ class DeleteAccountDialog extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_delete_account),
|
||||
title: Text(l10n.s_delete_account),
|
||||
actions: [
|
||||
TextButton(
|
||||
key: keys.deleteButton,
|
||||
@ -49,14 +49,14 @@ class DeleteAccountDialog extends ConsumerWidget {
|
||||
await ref.read(withContextProvider)(
|
||||
(context) async {
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, l10n.l_account_deleted);
|
||||
showMessage(context, l10n.s_account_deleted);
|
||||
},
|
||||
);
|
||||
} on CancellationException catch (_) {
|
||||
// ignored
|
||||
}
|
||||
},
|
||||
child: Text(l10n.w_delete),
|
||||
child: Text(l10n.s_delete),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
|
@ -45,9 +45,9 @@ Widget oathBuildActions(
|
||||
final theme = Theme.of(context).colorScheme;
|
||||
return SimpleDialog(
|
||||
children: [
|
||||
ListTitle(l10n.w_setup, textStyle: Theme.of(context).textTheme.bodyLarge),
|
||||
ListTitle(l10n.s_setup, textStyle: Theme.of(context).textTheme.bodyLarge),
|
||||
ListTile(
|
||||
title: Text(l10n.l_add_account),
|
||||
title: Text(l10n.s_add_account),
|
||||
key: keys.addAccountAction,
|
||||
leading:
|
||||
const CircleAvatar(child: Icon(Icons.person_add_alt_1_outlined)),
|
||||
@ -87,11 +87,11 @@ Widget oathBuildActions(
|
||||
}
|
||||
: null,
|
||||
),
|
||||
ListTitle(l10n.w_manage,
|
||||
ListTitle(l10n.s_manage,
|
||||
textStyle: Theme.of(context).textTheme.bodyLarge),
|
||||
ListTile(
|
||||
key: keys.customIconsAction,
|
||||
title: Text(l10n.l_custom_icons),
|
||||
title: Text(l10n.s_custom_icons),
|
||||
subtitle: Text(l10n.l_set_icons_for_accounts),
|
||||
leading: const CircleAvatar(
|
||||
child: Icon(Icons.image_outlined),
|
||||
@ -108,7 +108,7 @@ Widget oathBuildActions(
|
||||
ListTile(
|
||||
key: keys.setOrManagePasswordAction,
|
||||
title: Text(
|
||||
oathState.hasKey ? l10n.l_manage_password : l10n.l_set_password),
|
||||
oathState.hasKey ? l10n.s_manage_password : l10n.s_set_password),
|
||||
subtitle: Text(l10n.l_optional_password_protection),
|
||||
leading: const CircleAvatar(child: Icon(Icons.password_outlined)),
|
||||
onTap: () {
|
||||
@ -120,7 +120,7 @@ Widget oathBuildActions(
|
||||
}),
|
||||
ListTile(
|
||||
key: keys.resetAction,
|
||||
title: Text(l10n.l_reset_oath),
|
||||
title: Text(l10n.s_reset_oath),
|
||||
subtitle: Text(l10n.l_factory_reset_this_app),
|
||||
leading: CircleAvatar(
|
||||
foregroundColor: theme.onError,
|
||||
|
@ -48,7 +48,7 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
if (result) {
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
showMessage(context, AppLocalizations.of(context)!.l_password_set);
|
||||
showMessage(context, AppLocalizations.of(context)!.s_password_set);
|
||||
} else {
|
||||
setState(() {
|
||||
_currentIsWrong = true;
|
||||
@ -64,12 +64,12 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
(!widget.state.hasKey || _currentPassword.isNotEmpty);
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_manage_password),
|
||||
title: Text(l10n.s_manage_password),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: isValid ? _submit : null,
|
||||
key: keys.savePasswordButton,
|
||||
child: Text(l10n.w_save),
|
||||
child: Text(l10n.s_save),
|
||||
)
|
||||
],
|
||||
child: Padding(
|
||||
@ -85,9 +85,9 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
key: keys.currentPasswordField,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_current_password,
|
||||
labelText: l10n.s_current_password,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
errorText: _currentIsWrong ? l10n.l_wrong_password : null,
|
||||
errorText: _currentIsWrong ? l10n.s_wrong_password : null,
|
||||
errorMaxLines: 3),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
@ -111,7 +111,7 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
if (result) {
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
showMessage(context, l10n.l_password_removed);
|
||||
showMessage(context, l10n.s_password_removed);
|
||||
} else {
|
||||
setState(() {
|
||||
_currentIsWrong = true;
|
||||
@ -119,18 +119,18 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Text(l10n.l_remove_password),
|
||||
child: Text(l10n.s_remove_password),
|
||||
),
|
||||
if (widget.state.remembered)
|
||||
OutlinedButton(
|
||||
child: Text(l10n.l_clear_saved_password),
|
||||
child: Text(l10n.s_clear_saved_password),
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(oathStateProvider(widget.path).notifier)
|
||||
.forgetPassword();
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
showMessage(context, l10n.l_password_forgotten);
|
||||
showMessage(context, l10n.s_password_forgotten);
|
||||
},
|
||||
),
|
||||
],
|
||||
@ -143,7 +143,7 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_new_password,
|
||||
labelText: l10n.s_new_password,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
enabled: !widget.state.hasKey || _currentPassword.isNotEmpty,
|
||||
),
|
||||
@ -164,7 +164,7 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_confirm_password,
|
||||
labelText: l10n.s_confirm_password,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
enabled:
|
||||
(!widget.state.hasKey || _currentPassword.isNotEmpty) &&
|
||||
|
@ -42,12 +42,12 @@ class OathScreen extends ConsumerWidget {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ref.watch(oathStateProvider(devicePath)).when(
|
||||
loading: () => MessagePage(
|
||||
title: Text(l10n.w_authenticator),
|
||||
title: Text(l10n.s_authenticator),
|
||||
graphic: const CircularProgressIndicator(),
|
||||
delayedContent: true,
|
||||
),
|
||||
error: (error, _) => AppFailurePage(
|
||||
title: Text(l10n.w_authenticator),
|
||||
title: Text(l10n.s_authenticator),
|
||||
cause: error,
|
||||
),
|
||||
data: (oathState) => oathState.locked
|
||||
@ -66,7 +66,7 @@ class _LockedView extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return AppPage(
|
||||
title: Text(AppLocalizations.of(context)!.w_authenticator),
|
||||
title: Text(AppLocalizations.of(context)!.s_authenticator),
|
||||
keyActionsBuilder: (context) =>
|
||||
oathBuildActions(context, devicePath, oathState, ref),
|
||||
child: Padding(
|
||||
@ -116,10 +116,10 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
|
||||
.select((value) => value?.length));
|
||||
if (numCreds == 0) {
|
||||
return MessagePage(
|
||||
title: Text(l10n.w_authenticator),
|
||||
title: Text(l10n.s_authenticator),
|
||||
key: keys.noAccountsView,
|
||||
graphic: noAccounts,
|
||||
header: l10n.l_no_accounts,
|
||||
header: l10n.s_no_accounts,
|
||||
keyActionsBuilder: (context) => oathBuildActions(
|
||||
context, widget.devicePath, widget.oathState, ref,
|
||||
used: 0),
|
||||
@ -154,7 +154,7 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
|
||||
style: textTheme.titleMedium
|
||||
?.copyWith(fontSize: textTheme.titleSmall?.fontSize),
|
||||
decoration: InputDecoration(
|
||||
hintText: l10n.l_search_accounts,
|
||||
hintText: l10n.s_search_accounts,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(32)),
|
||||
),
|
||||
|
@ -73,7 +73,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
|
||||
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop(renamed);
|
||||
showMessage(context, l10n.l_account_renamed);
|
||||
showMessage(context, l10n.s_account_renamed);
|
||||
} on CancellationException catch (_) {
|
||||
// ignored
|
||||
} catch (e) {
|
||||
@ -127,12 +127,12 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
|
||||
final isValid = isUnique && isValidFormat;
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_rename_account),
|
||||
title: Text(l10n.s_rename_account),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: didChange && isValid ? _submit : null,
|
||||
key: keys.saveButton,
|
||||
child: Text(l10n.w_save),
|
||||
child: Text(l10n.s_save),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
@ -151,7 +151,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
|
||||
key: keys.issuerField,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_issuer_optional,
|
||||
labelText: l10n.s_issuer_optional,
|
||||
helperText: '', // Prevents dialog resizing when disabled
|
||||
prefixIcon: const Icon(Icons.business_outlined),
|
||||
),
|
||||
@ -170,7 +170,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
|
||||
key: keys.nameField,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.l_account_name,
|
||||
labelText: l10n.s_account_name,
|
||||
helperText: '', // Prevents dialog resizing when disabled
|
||||
errorText: !isValidFormat
|
||||
? l10n.l_account_name_required
|
||||
|
@ -32,7 +32,7 @@ class ResetDialog extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_factory_reset),
|
||||
title: Text(l10n.s_factory_reset),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
@ -42,7 +42,7 @@ class ResetDialog extends ConsumerWidget {
|
||||
showMessage(context, l10n.l_oath_application_reset);
|
||||
});
|
||||
},
|
||||
child: Text(l10n.w_reset),
|
||||
child: Text(l10n.s_reset),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
|
@ -79,8 +79,8 @@ class _UnlockFormState extends ConsumerState<UnlockForm> {
|
||||
obscureText: _isObscure,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.w_password,
|
||||
errorText: _passwordIsWrong ? l10n.l_wrong_password : null,
|
||||
labelText: l10n.s_password,
|
||||
errorText: _passwordIsWrong ? l10n.s_wrong_password : null,
|
||||
helperText: '', // Prevents resizing when errorText shown
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: IconButton(
|
||||
@ -111,7 +111,7 @@ class _UnlockFormState extends ConsumerState<UnlockForm> {
|
||||
minLeadingWidth: 0,
|
||||
)
|
||||
: CheckboxListTile(
|
||||
title: Text(l10n.l_remember_password),
|
||||
title: Text(l10n.s_remember_password),
|
||||
dense: true,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
value: _remember,
|
||||
@ -127,7 +127,7 @@ class _UnlockFormState extends ConsumerState<UnlockForm> {
|
||||
alignment: Alignment.centerRight,
|
||||
child: ElevatedButton.icon(
|
||||
key: keys.unlockButton,
|
||||
label: Text(l10n.w_unlock),
|
||||
label: Text(l10n.s_unlock),
|
||||
icon: const Icon(Icons.lock_open),
|
||||
onPressed: _passwordController.text.isNotEmpty ? _submit : null,
|
||||
),
|
||||
|
@ -39,7 +39,7 @@ class SettingsPage extends ConsumerWidget {
|
||||
final theme = Theme.of(context);
|
||||
final enableTranslations = ref.watch(communityTranslationsProvider);
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.w_settings),
|
||||
title: Text(l10n.s_settings),
|
||||
child: Theme(
|
||||
// Make the headers use the primary color to pop a bit.
|
||||
// Once M3 is implemented this will probably not be needed.
|
||||
@ -52,9 +52,9 @@ class SettingsPage extends ConsumerWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ListTitle(l10n.w_appearance),
|
||||
ListTitle(l10n.s_appearance),
|
||||
RadioListTile<ThemeMode>(
|
||||
title: Text(l10n.l_system_default),
|
||||
title: Text(l10n.s_system_default),
|
||||
value: ThemeMode.system,
|
||||
groupValue: themeMode,
|
||||
onChanged: (mode) {
|
||||
@ -63,7 +63,7 @@ class SettingsPage extends ConsumerWidget {
|
||||
},
|
||||
),
|
||||
RadioListTile<ThemeMode>(
|
||||
title: Text(l10n.l_light_mode),
|
||||
title: Text(l10n.s_light_mode),
|
||||
value: ThemeMode.light,
|
||||
groupValue: themeMode,
|
||||
onChanged: (mode) {
|
||||
@ -72,7 +72,7 @@ class SettingsPage extends ConsumerWidget {
|
||||
},
|
||||
),
|
||||
RadioListTile<ThemeMode>(
|
||||
title: Text(l10n.l_dark_mode),
|
||||
title: Text(l10n.s_dark_mode),
|
||||
value: ThemeMode.dark,
|
||||
groupValue: themeMode,
|
||||
onChanged: (mode) {
|
||||
@ -84,7 +84,7 @@ class SettingsPage extends ConsumerWidget {
|
||||
basicLocaleListResolution(window.locales, officialLocales) !=
|
||||
basicLocaleListResolution(
|
||||
window.locales, AppLocalizations.supportedLocales)) ...[
|
||||
ListTitle(l10n.w_language),
|
||||
ListTitle(l10n.s_language),
|
||||
SwitchListTile(
|
||||
title: Text(l10n.l_enable_community_translations),
|
||||
subtitle: Text(l10n.p_community_translations_desc),
|
||||
|
@ -62,8 +62,8 @@ class _ResponsiveDialogState extends State<ResponsiveDialog> {
|
||||
} else {
|
||||
// Dialog
|
||||
final cancelText = widget.onCancel == null && widget.actions.isEmpty
|
||||
? l10n.w_close
|
||||
: l10n.w_cancel;
|
||||
? l10n.s_close
|
||||
: l10n.s_cancel;
|
||||
return AlertDialog(
|
||||
title: widget.title,
|
||||
titlePadding: const EdgeInsets.only(top: 24, left: 18, right: 18),
|
||||
|
@ -38,7 +38,7 @@ InputCounterWidgetBuilder buildByteCounterFor(String currentValue) =>
|
||||
return Text(
|
||||
maxLength != null ? '${byteLength(currentValue)}/$maxLength' : '',
|
||||
style: style,
|
||||
semanticsLabel: AppLocalizations.of(context)!.l_character_count,
|
||||
semanticsLabel: AppLocalizations.of(context)!.s_character_count,
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user